再不来电脑我可能得疯
完了,今天看完估计晚上做梦都要是内存泄露了…
今天是OC和IOS混合双打嗷~
OC部分
并发性
可以使用GCD来管理并发性
@synchronized拥有一个参数,这个对象是可修改的,可以确保不同的线程能够连续访问临界区的代码
如果一个线程属性值不会被多个线程访问的话,可以添加nonatomic特性,可以提高性能。因为这样编译器会生成@synchronize(mutex, atomic)来保证互斥
performSelectorInBackground:withObject方法可以在后台执行一个方法。通过创建一个线程来运行方法
需要注意以下限制
- 这些方法运行在各自的线程里,因此必须为这些Cocoa对象创建一个自动释放池,主自动释放池是与主线程相关的
- 这些方法不能有返回值,可以有一个或者没有参数即
1 2 |
- (void)myMethod; - (void)myMethod:(id)myObject; |
如果要后台执行方法,调用performSelectorInBackground:withObject方法即可,withObject即为传入函数的参数
调度队列:
- 连续队列:按照顺序执行任务,可以创建任意多个,会并行操作任务。只要任务异步提交,就会并行操作
- 并发队列:每个并发队列都能并发执行一个或者多个任务。任务会根据指派到队列的顺序开始执行。无法创建连续队列,只能从系统中提供的三个队列进行执行
- 主队列:是应用程序中有效的主队列,执行的是主线程任务
连续队列
按照一定顺序执行的任务可以使用连续队列,任务执行顺序为先进先出
1 2 |
dispatch_queue_t my_serial_queue; my_serial_queue = dispatch_queue_create("com.apress.MySerialQueue1", NULL); |
第一个参数是队列名称、第二个参数是队列的特性
并发队列
一次所运行的任务数量无法预测,一个任务可能在前一个任务结束前就执行
三个并发队列:高优先级(DISPATCH_QUEUE_PRIORITY_HIGH)、默认优先级(DISPATCH_QUEUE_PRIORITY_DEFAULT)、低优先级(DISPATCH_QUEUE_PRIORITY_LOW)
1 2 |
dispatch_queue_t myQueue; myQueue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); |
主队列
这个队列和主线程有关,需要注意队列中的任务顺序,否则可能会阻塞主应用程序运行。通常要以同步方式使用这个队列,提交多个任务并在它们操作完毕后执行这些动作
1 |
dispatch_queue_t main_queue = dispatch_get_main_queue(void); |
获取当前队列
可以使用dispatch_get_current_queue来获取当前运行的队列代码块
清理数据
1 2 3 4 |
void finalizer (void *context){ NSMutableDictionary *theData = (__bridge_transfer NSMutableDictionary *) context; [theData removeAllObjects]; } |
__bridge_transfer关键字用于将内存管理从全局释放池转移到我们的函数
访问上下文内容使用
1 2 |
NSMutableDictionary *myContext = (__bridge NSMutableDictionary *) dispatch_get_context(dispatch_get_current_queue()); |
NSBlockOperation
创建代码块操作可以创建这个操作并让队列执行它
1 2 3 |
NSBlockOperation *blockOperator = [NSBlockOperator blockOperationWithBlock:^{ // ... }]; |
该方法类似于需要执行代码块的dispatch_async函数
NSInvocationOperation
如果已经拥有一个可以完成工作的类,并且希望在队列上执行的话,可以采用这种方法
OC中使用@property定义了一个指针后会自动创建一个前面带下划线的变量来作为这个指针指向的位置
IOS部分
Web交互
JSCore可以调用Native组件执行JS代码
我们可以设计很多的JS Open API
在实际业务中,还可以使用一部分模板引擎等
动画
底层部分是Core Animation
UIView自带动画:渐隐渐显、位置移动
处理基本的Frame、Alpha、Tranform
实现只需要设置动画参数:动画、效果、终止时的属性最终值
UIKit组件自带动画:UITableViewCell添加删除
UIViewController切换
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 |
//上面修改协议 cell.delegate = self; - (void) deleteButtonClick(){ } @interface ... @property (nonatomic, strong, readwrite) UIView *backgroundView; @property (nonatomic, strong, readwrite) UIButton *deleteButton; @end @implementation ... - (instancetype)initWithFrame:(CFRect)frame{ self = [super initWithFrame:frame]; if(self){ [self addSubview:({ _backgroundView = [[UIView alloc]initWithFrame:self.bounds]; _backgroundView.backgroundColor = [UIColor blackColor]; [_backgroundView addGestureRecognizer:({ UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(_clickButton) forControlEvents:UIControlEventTouchUpInside]; })]; _backgroundView.alpha = 0.5; _backgroundView; })]; [self addSubview:({ _deleteButton = [[UIButton alloc]initWithFrame:CGRectMake(0, 0, 200, 200)]; [_deleteButton addTarget:self action:@selector(_clickButton) forControlEvents:UIControlEventTouchUpInside]; _deleteButton.backgroundColor = [UIColor blueColor]; _deleteButton; })]; } } - (void)showDeleteView{ [[UIAppliction sharedApplication].keyWindow addSubview:self]; [UIView animateWithDuration: 1.f animations:^{ self.deleteButton.frame = CGRectMake((self.bounds.size.width - 200)/2, (self.bounds.size.height-200)/2, 200, 200));//时间1s [UIView animateWithDuraction 1.f delay: 0.f usingSpringWithDamping:0.5 initialSpringVelocity:0.5 options:UIViewAnimationOptionCurveEaseInOut animations: ^{ self.deleteButton.frame = CGRectMake((self.bounds.size.width - 200)/2, (self.bounds.size.height - 200)/2, 200, 200); } completion:^(BOOL finished) { ... //结束的时候做的工作 }] }];//动画时间1s、时间延迟0s、阻尼系数0.5s,options是前后快中间慢 //动画 }//声明为public - (void)dismissDeleteView{ [self removeFromSuperview]; } - (void)_clickButon{ [self removeFromSuperview];//删除掉所有的view } - (void) tableViewCell:(UITableViewCell *)tavleViewCell clickDeleteButton:(UIButton *) deleteButton{ GTDeleteCellView *view = [[GTDeleteCellView alloc]initWithFrame:self.view.bounds]; } |
– (void) tableViewCell:中间可以添加删除cell的逻辑
CALayer
每个UIView都有一个CALayer负责内容的绘制和动画
UIKit其他组件对应的展示Layer
和UIView具有相同的结构,本身可以包含subLayer
一般来说不会直接重写CALayer,系统内置不少了Layer
Cell变成圆角的:
1 2 3 4 |
self.deleteButton.layer.cornerRadius = 10;//圆角半径 self.deleteButton.layer.masksToBounds = YES;//使得面和边界匹配 layer.borderColor//边界颜色 layer.borderWidth//宽度 |
CoreAnimation
CABaseAnimation 基本动画
CAKeyFrameAnimation 关键路径动画,中间不同时间点
CAAnimationGroup 复杂动画都可以分解成多个简单动画
CATransition 转场动画 – UIViewController
CAEmitterLayer
粒子发射器
动画更多实现开源框架:Lottie、facebook / pop;
常用代码规范
Xcode提供
- Refactor
- 注释option + commend + /
- 编译器指令 #pragma mark
命名规范
- 变量名
- 函数名
#pragma mark
用法#pragma mark – UITableViewDelegate…
这样在Xcode中可以很方便的显示类似的文本
目录结构可以创建文件夹来管理文件
插件XCFormat
可以自定义格式进行Format
访问网址
NSURL
网站地址
格式:[协议类型]://[服务器地址]:[端口号]/[资源层级UNIX文件路径][文件名]?[查询]#[片段ID]
作用:分解成一部分子字符串,可以很方便的进行调用等操作
URLWithString 传入一个NSString *来生成一个地址
本地文件路径:fileURLWithPath(NSString *) path或fileURLWithPath(NSString *) path relaticeToURL:(nullable NSURL *)baseURLNSURLRequest
请求参数/设置等
Http header设置 NSString *HTTPMethod;
get/post方法 NSData *HTTPBody;
NSURLSession
接受资源数据
负责接受、发送和处理请求
一个App可以创建多个不同配置的多个Session,类似于无痕模式和普通模式
一个Session可以创建多个请求,类比浏览器打开多个网页Request可以封装为一个Task
一般使用sessionWithConfiguration,可以配置timeout、cookie、最大并发数等
系统也给我们提供了一个sharedSession
1 2 3 4 5 6 7 8 9 10 |
self.listLoader = [[GTListLoader alloc]init]; [self.listLoader loadListData]; - (void) loadListData{ NSString *urlString = @"http://toutiao.com"; NSURL *listURL = [NSURL URLWithString:urlString]; NSURLRequest *listRequest = [NSURLRequest requestWithURL:listURL]; NSURLSession *session = [NSURLSession shardSession]; NSURLSessionDataTask *dataTask = [session dataTaskWithRequest:listRequest];//封装Task } //在webView内部使用loadRequest:(NSURLRequest)方法调用该方法即可 |
NSURLSessionDelegate用于回调
NSURLSessionTast状态
suspend:挂起
resume:开始执行
cancel:取消
刚创建的SessionTask默认是suspend状态
处理response时可以通过Handler block和Delegate
通过Handler block的话就采用代码块在dataTaskWithRequest:completionHandler:里面处理
通过Delegate有:
NSURLSessionTaskDelegate:处理证书、跳转等逻辑
NSURLSessionDataDelegate:处理数据
NSURLSessionDownloadDelegate:处理下载
NSURLSessionStreamDelegate:流处理
IOS9中存在AppTransportSecurity特性,默认需要用https进行请求需要进行设置才可以加载http资源
具体步骤如下:
- 创建 & 使用默认Session
- 通过地址和参数创建Task
- 开始 & 取消Task
- 在Handler中处理数据
1 2 3 4 5 6 7 8 9 10 |
- (void) loadListData{ NSString *urlString = @"http://toutiao.com"; NSURL *listURL = [NSURL URLWithString:urlString]; NSURLSession *session = [NSURLSession shardSession]; NSURLSessionDataTask *dataTask = [session dataTaskWithURL:listURL completionHandler: ^(NSData *_Nullable data, NSURLResponse *_Nullable response, NSError *_Nullable error){ ... }];//封装Task [dataTask resume]; } //在webView内部使用loadRequest:(NSURLRequest)方法调用该方法即可 |
Project & Workspace
Workspace可以继承Project
但是大量第三方库的使用会产生互相引用和依赖。
另外依赖配置、编译参数、及时更新、版本管理等
常用代码管理方式
- Git submodule 基于git,使用简单,功能较少,只能现在全部项目
- Cocoapods 基于Ruby语言,中心化的管理(出现问题会宕机),会生成一个workspace
- Carthage Swift语言,提供framework文件
cocoapods中我们需要写一个podfile来进行集成,会进行自动下载Code,然后会生成pods,然后和我们的Project生成一个wordspace
podfile例子:
1 2 3 |
target 'SampleApp' do pod 'AFNetworing' end |
然后执行pod install 默认下载最新版本
Pods文件夹下忽悠一个AFNetworking文件夹
Pod update可以用于更新
以后需要打开Workspace而不是这个project
使用的时候修改
AFNetwoking的一部分操作
[[AFHTTPSectionManager manager]GET@”…” parameters:nil process:^{
}success:^{} failure:^{}];
JSON解析
基本数据:
- Number
- Boolean
- String
- Null
- Array
- Object (Dictionary)
Google的protobuf(二进制流)
AFHTTPSessionManager中的response已经解析好了
提供JSON数据和系统对象
+ dataWithJSONObject:options:error: 转换成JSON data
+ JSONObjectWithData:options:error: 从JSONdata中返回一个对象(一般是NSDictionary)
我们一般会创建一个新的类,里面包含大量的字段,作为一个结构化数据类
例如:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
@interface ... @property(nonatomic, copy,readwrite) NSString *category; @property(nonatomic, copy,readwrite) NSString *picUrl; @property(nonatomic, copy,readwrite) NSString *uniqueKey; @property(nonatomic, copy,readwrite) NSString *title; @property(nonatomic, copy,readwrite) NSString *date; @property(nonatomic, copy,readwrite) NSString *authorName; @property(nonatomic, copy,readwrite) NSString *articleUrl; @end @implemation ... - (void) configWithDictionary:(NSDictionary *)dictionary{ #warning 注意类型匹配判断 self.category = [dictionary objectForKey:@"category"]; self.picUrl = [dictionary objectForKey:@"thumbnail_pic_s"]; self.uniqueKey = [dictionary objectForKey:@"uniquekey"]; self.title = [dictionary objectForKey:@"title"]; self.date = [dictionary objectForKey:@"date"]; self.authorName = [dictionary objectForKey:@"author_name"]; self.articleUrl = [dictionary objectForKey:@"url"]; }; @end //调用的函数 NSArray *dataArray = [((NSDictionary *)[(NSDictionary *)jsonObj) objectForKey:@"result"]) objectForKey:@"data"]; NSMutableArray *listItemArray = @[].mutableCopy; for(NSDictionary *info in dataArray){ .. = [[... alloc]init]; [.. configWithDictionary:info]; [listItemArray addObject:..]; } |
此时Array中都是刚才读入的数据了
JSON Model开源项目
为了简化NSData – JSON – Model
常用的开源项目:YYModel Mantle MJExtension
我们可以由这些数据进行一个完整的列表加载:
- 网络接口加载
- 使用NSJsonSerializaion解析处理网络请求
- 数据Model化
- 列表加载Model数组
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 |
@class GTListItem; typedef void(^FinishBlock)(BOOL success, NSArray<GTListItem *> *dataArray); @interface -(void)loadListDataWithFinishBlock:(FinishBlock)finishblock; @end //请求部分 dispatch_async(dispatch_get_main_queue(), ^{ if(finishBlock){ finishBlock(error == nil, listItemArray.copy); } });//回调到主线程 if(finishBlock){ finishBlock(error == nil,listItemArray.copy); } //didLoad部分 __weak typeof(self)wself = self; [self.listLoader loadListDataWithFinishBlock:^(BOOL success, NSArray<..*> ...dataArray){ __strong typeof(wself) strongSelf = wself; strongSelf.dataArray = dataArray; [strongSelf.tableView reloadData]; }]; //内部重写函数 - (void)layoutTableViewCellWithItem:(GTListItem *)item{ self.titleLabel.text = item.title; ... UIImage *image = [UIImage imageWithData:[NSData dataWIthContentsOfURL:[NSURL URLWithString:item.picUrl]]; self.rightImage = image; } |
注意:在代码块前面将self转为weak是为了解决循环引用的问题,也就是Block引用了Object会导致内存泄漏的情况 知识链接(感谢之夏哥哥)
呜呜,真的要做梦都是内存泄露了…
0 条评论