多线程-GCD、NSOPeration
1、 多线程 --生命周期:新建、就绪、运行、组赛、死亡
// 在多线程中使用定时器必须开启Runloop.
[[NSRunLoop currentRunLoop] run];
1.NSThread
1> 开线程的几种方式
-
先创建,后启动
NSThread *thread = [[NSThread alloc] initWithTarget:self selector:@selector(run) object:nil];
[thread start]; -
直接启动
[NSThread detachNewThreadSelector:@selector(run) toTarget:self withObject:nil];
[self performSelectorInBackground:@selector(run) withObject:nil];
2、其他用法
NSThread *current = [NSThread currentThread];
+ (NSThread *)mainThread; // 获得主线程
3 线程间通信
performSelectorOnMainThread.....
什么情况下选择GCD,和 NSOperationQueue呢? 依赖强选择后者。
-2.GCD(重点--把任务(线程)添加到队列里)
1> 队列的类型
//* 并发队列
获得全局的并发队列: dispatch_get_global_queue
//* 串行队列
a.自己创建
dispatch_queue_create
b.主队列
dispatch_get_main_queue
2> 执行任务的方法类型
- 同步(sync)执行
- 异步(async)执行
3> 了解队列和方法的配合使用
4> 线程间通信
dispatch_async(
dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 执行耗时的异步操作...(全局队列,由系统自动调用,在子线程中调用)
dispatch_async(dispatch_get_main_queue(), ^{
// 回到主线程,执行UI刷新操作
});
});
5> 其他用法
dispatch_once
dispatch_after
dispatch_group_async\dispatch_group_notify
3.NSOperation
1> 基本使用
NSInvocationOperation
NSBlockOperation
// 2> NSOperationQueue(重点)
- 最大并发数设置
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
- 设置依赖(面试题)
[operationB addDependency:operationA]; // 操作B依赖于操作A
3> 如何解决一张图片(一个url)重复下载的问题?
// 答:利用Operation缓存操作,(key值 ,URL)根据图片的URL去images中取得图片,判断是否存在,存在直接显示,否则,显示占位图片,然后根据图片的URL去查看operation中是否存在下载操作,存在,则下载,否则创建下载操作,下载后放到images文件中保存
4、 自定义Operation(基本流程)
- 自定义方法的步骤:
- 1、重写main方法,自己创建自动释放池(因为异步操作,无法访问主线程的自动释放池)
- 2、在main方法中实现具体操作
// 重写- (void)main方法的注意点
// 自己创建自动释放池(因为如果是异步操作,无法访问主线程的自动释放池)
// 经常通过- (BOOL)isCancelled方法检测操作是否被取消,对取消做出响应
- (void)main
{
@autoreleasepool {
// 正规写法,经常检查操作是否被取消,必须判断
if (self.isCancelled) return;
NSURL *downloadUrl = [NSURL URLWithString:self.url];
NSData *data = [NSData dataWithContentsOfURL:downloadUrl]; // 这行会比较耗时
if (self.isCancelled) return;
UIImage *image = [UIImage imageWithData:data];
if (self.isCancelled) return;
if ([self.delegate respondsToSelector:@selector(downloadOperation:didFinishDownload:)]) {
dispatch_async(dispatch_get_main_queue(), ^{ // 回到主线程, 传递图片数据给代理对象
[self.delegate downloadOperation:self didFinishDownload:image];
});
}
}
bolck 的使用?
-
声明一个block
1> @property (nonatomic, copy) void (testBlock^)(); // 使用 copy// 1.如果没有对block进行copy操作,block就存储于 [栈空间](指针)
// 2.如果对block进行copy操作,block就存储于 [堆空间](app管理)// 3.如果block存储于栈空间,不会对block内部所用到的对象产生强引用
// 4.如果block存储于堆空间,就会对block内部所用到的对象产生强引用
Person *p = [[Person alloc]init];
__weak typeof(p) weakP = p;
p.testBlock = ^ {
[weakP run]; // 强引用
};2> block
(1)、block的内存管理
(2)、防止循环(retain)ARC :__weak , 非ARC __block