NSOperation
- 一个NSOperation就是一个操作,可以拥有至少一个任务,它可以调用start方法执行任务,默认是同步执行,即在主线程执行
- 作用:配合使用NSOperation和NSOperationQueue,可以实现多线程编程(即可异步执行任务)
-
NSOperation子类
- NSOperation是一个抽象类,不具备封装任务(操作)的能力,必须使用它的子类进行封装
- 使用NSOperation子类的方式有3种:
- NSInvocationOperation (少用)
// 如果不添加到队列中,则在主线程上运行操作 NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(run) object:nilo]; [op start];
- NSBlockOperation,如果不添加到队列中,第一个block在主线程运行,添加的额外block在子线程上执行
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"任务1--%@", [NSTread currentTread]) // 主线程 }]; [op addExecutionBlock:^{ NSLog(@"任务2--%@", [NSTread currentTread]) // 子线程 }]; [op addExecutionBlock:^{ NSLog(@"任务3--%@", [NSTread currentTread]) // 子线程 }]; [op addExecutionBlock:^{ NSLog(@"任务4--%@", [NSTread currentTread]) // 子线程 }];
- 自定义子类继承NSOperation,实现内部相应的方法
// main方法是入口,必须将任务放到main方法中才会执行 - (void)main {...};
NSOperationQueue
NSOperationQueue是基于GCD的面向对象的队列
- NSOperationQueue队列类型
- 主队列:任务在主线程执行
[NSOperationQueue mainQueue];
- 其他队列(串行、并发):任务在子线程执行
// 默认并发 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 实现串行,可设置 maxConcurrentOperationCount 属性 = 1,其默认值是 -1 queue.maxConcurrentOperationCount = 1;
- GCD的队列类型
- 并发队列:
- 自己创建的
- 全局的
- 串行队列:
- 主队列
- 自己创建的
-
实现多线程的步骤
-
方式一:
- 创建队列:NSOperationQueue
- 创建操作:NSOperation
- 将NSOperation对象添加到NSOperationQueue中(系统会自动将NSOperationQueue中的NSOperation取出来,并自动放到一条线程中执行任务)
- 主线程里执行:放到主队列
- 子线程里执行:放到其他队列(即创建的队列)
-
方式二:
- 创建队列:NSOperationQueue
- 直接将任务添加到队列中。
具体实现
/** 方式一 **/ // 1. 创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 2. 创建操作(任务) // 操作1任务1 NSInvocationOperation NSInvocationOperation *op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil]; // 操作2任务2 NSBlockOperation NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{...}]; // 操作2任务3 NSBlockOperation [op2 addExecutionBlock:^{...}]; // 操作3任务4 使用自定义JKYOperation,该类中需要实现-(void)main方法,并将任务添加其中,才会执行的任务 JKYOperation *op3 = [[JKYOperation alloc] init]; // 3. 添加任务到队列中 [queue addOperation:op1]; [queue addOperation:op2]; [queue addOperation:op3]; /** 方式二 **/ // 1. 创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 2. 添加任务 [queue addOperationWithBlock:^{...}];
-
-
队列的挂起与取消
队列执行挂起或取消的同时,operation的任务还在执行,则会执行完当前任务,再停止。
- 苹果推荐的解决方案:
自定义NSOperation,并在类中相对耗时的任务后判读当前队列是否处于暂停或取消状态,如果是则return;
-(void)main { //耗时任务执行后,判断 if(self.isCanceled || self.isSusended) return; }
-
操作依赖和监听
在多线程中,并发执行多个操作,无法控制其调用顺序,可添加依赖实现顺序调用
具体实现
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{...}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{...}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{...}];
/** 监听 **/
op3.completionBlock = ^{NSLog(@"op3执行完毕");};
/** 依赖 **/
// op3依赖op1,op3依赖op2
// 可跨队列添加依赖
[op3 addDependency:op1];
[op3 addDependency:op2];
[queue addOperation:op1];
[queue addOperation:op2];
[queue addOperation:op3];
//
// 注意:
// 1. 应在加入队列之前添加依赖
// 2. 不可两个操作相互添加依赖
-
线程之间通信
具体实现
[[NSOperationQueue alloc] init] addOperationWithBlock:^{
// 图片的网络路径
NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/123234.jpg"];
// 加载图片
NSData *data = [NSDdata dataWithContentsOfURL:url];
// 生成图片
UIImage *image = [UIImage imageWithData:data];
// 回到主线程
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}]
网友评论