- 配合使用NSOperation和NSOperationQueue也能实现多线程编程
- NSOperation是个抽象类,并不具备封装操作的能力,必须使用它的子类
- NSInvocationOperation
- NSBlockOperation
- 自定义子类继承NSOperation,实现内部相应的
main
方法
- NSOperationQueue的作用
- NSOperation可以调用start方法来执行任务,但默认是同步执行的
- 如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作
- 添加方法1:- (void)addOperation:(NSOperation *)op;
- 添加方法2:- (void)addOperationWithBlock:(void (^)(void))block;
- NSOperation是个抽象类,并不具备封装操作的能力,必须使用它的子类
- 使用NSInvocationOperation实现多线程编程
- 步骤:
- 封装操作
initWithTarget
- 实现操作对应的方法
sel
- 启动操作
start
- 封装操作
-
注意
- 默认情况下,调用了start方法后并不会开一条新线程去执行操作,而是在当前线程同步执行操作
- 只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作
- 步骤:
- 使用NSBlockOperation实现多线程编程
- 步骤:
- 封装操作
blockOperationWithBlock
- 追加操作
addExecutionBlock:
(此步骤可以省略,即可以追加操作也可以不追加操作) - 启动操作
start
- 封装操作
-
注意
- 只要NSBlockOperation封装的操作数>1,就会异步执行操作
- 即只有追加操作,才会异步执行操作
- 步骤:
- 自定义子类继承NSOperation,实现内部相应的
main
方法- 创建自定义的子类继承NSOperation
- 在子类中实现内部相应的
main
方法- 自己创建自动释放池(因为如果是异步操作,无法访问主线程的自动释放池)
- 经常通过-(BOOL)isCancelled方法检测操作是否被取消,对取消做出响应
- 实例化子类对象,并实现操作
- 使用NSInvocationOperation和NSOperationQueue实现多线程编程
- 步骤
- 封装操作
- 创建队列
- 主队列
mainQueue
(凡是在主队列中的任务都在主线程中执行&串行队列) - 非主队列
[[NSOperationQueue alloc]init]
(同时具备了并发和串行的功能,默认是并发队列)
- 主队列
- 把操作添加到队列中
- addOperation:
- addOperationWithBlock:
- 步骤
- 并发数
- 概念:同时执行的任务数
- 必须在操作添加到队列之前设置最大并发数的个数
- 最大并发数的方法
- (NSInteger)maxConcurrentOperationCount;
- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;
- 最大并发数量
- maxConcurrentOperationCount = 1 串行队列
- maxConcurrentOperationCount > 1 并发队列
- maxConcurrentOperationCount = -1 并发数不做限制,并发队列
- maxConcurrentOperationCount = 0 程序不能运行
- 同步执行任务的情况
- 仅使用NSInvocationOperation
- 仅使用NSBlockOperation
- 使用NSOperation和mainQueue
- 使用NSOperation和[[NSOperationQueue alloc]init]且最大并发数为0
- 队列的暂停、恢复、取消
- 队列的暂停
- -(void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列
- -(BOOL)isSuspended;
- 不能暂停当前处于执行状态的操作
- 只能停止后面没有处于执行状态的操作
- 暂停操作是可以恢复的
- 队列的恢复
- -(void)setSuspended:(BOOL)b; // YES代表暂停队列,NO代表恢复队列
- -(BOOL)isSuspended;
- 队列的取消
- 取消所有队列的操作-(void)cancelAllOperations;,内部调用每个操作的cancel方法
- 调用NSOperation的- (void)cancel方法取消单个操作
- 后面的任务将永远没有机会执行
- 取消操作是不能恢复的
- 实现步骤
- 在storyboard中拖拽开始执行、暂停、取消、恢复4个按钮
- 生成其对应的点击事件的方法
- 开始执行方法
- 使用NSBlockOperation封装操作
- 创建队列
- 设置最大并发数为1(保证程序串行执行)
- 把操作添加到队列
- 暂停方法
- 设置isSuspended属性为YES
- 取消方法
- 调用cancelAllOperations方法
- 恢复方法
- 设置isSuspended属性为NO
- 实现代码
- 队列的暂停
@interface ViewController ()
/** 队列 */
@property(nonatomic, strong)NSOperationQueue *queue;
@end
@implementation ViewController
/**
* 开始执行
*/
- (IBAction)startBtnClick {
// 创建操作对象
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 10000; i++) {
NSLog(@"1---%zd---main------%@", i,[NSThread currentThread]);
}
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 10000; i++) {
NSLog(@"2---%zd---main------%@", i,[NSThread currentThread]);
}
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
for (int i = 0; i < 10000; i++) {
NSLog(@"3---%zd---main------%@", i,[NSThread currentThread]);
}
}];
// 创建队列
self.queue = [[NSOperationQueue alloc] init];
// 设置最大并发数
self.queue.maxConcurrentOperationCount = 1;
// 把操作添加到队列
[self.queue addOperation:op1];
[self.queue addOperation:op2];
[self.queue addOperation:op3];
}
/**
* 暂停
*/
- (IBAction)suspendBtnClick {
[self.queue setSuspended:YES];
}
/**
* 取消
*/
- (IBAction)cancleBtnClick {
[self.queue cancelAllOperations];
}
/**
* 恢复
*/
- (IBAction)resumeBtnClick {
[self.queue setSuspended:NO];
}
@end
- 自定义NSOperatioin子类实现队列的取消
- 自定义NSOperatioin子类
- 重写main方法
- 在storyboard中拖拽开始执行、取消2个按钮
- 生成其对应的点击事件的方法
- 开始执行方法
- 使用自定义NSOperatioin子类封装操作
- 创建队列
- 设置最大并发数为1(保证程序串行执行)
- 把操作添加到队列
- 取消方法
- 调用cancelAllOperations方法
- 代码实现
// 控制器代码
@interface ViewController ()
/** 队列 */
@property(nonatomic, strong)NSOperationQueue *queue;
@end
@implementation ViewController
- (IBAction)startBtnClick {
// 封装操作
ZQOperation *op = [[ZQOperation alloc] init];
// 创建队列
self.queue = [[NSOperationQueue alloc] init];
// 设置最大并发数
self.queue.maxConcurrentOperationCount = 1;
// 把操作添加到队列
[self.queue addOperation:op];
}
- (IBAction)cancelBtnClick {
[self.queue cancelAllOperations];
}
@end
![](/Users/joyce/Desktop/%E5%B0%8F%E7%A0%81%E5%93%A5/%E7%AC%94%E8%AE%B0/%E5%A4%9A%E7%BA%BF%E7%A8%8B/images/Snip20160112_2.png)
-
操作的依赖、监听
- 操作的依赖
- NSOperation之间可以设置依赖来保证执行顺序
- 可以在不同queue的NSOperation之间创建依赖关系
- [operationB addDependency:operationA]; // 操作B依赖于操作A
- 不能设置循环依赖:A依赖B,B依赖A
- 设置依赖必须再把操作添加到队列之前
- 操作的监听
- -(void (^)(void))completionBlock;
- -(void)setCompletionBlock:(void (^)(void))block;
- 当要实现在A操作完成后实现B操作时需要监听A操作
- 操作的依赖
-
NSOperation实现线程间的通信(下载两张图片并合成)
- 思路
- 封装下载图片1操作download1
- 封装下载图片2操作download2
- 封装合成图片操作combie(绘图)
- 创建队列
- 设置操作依赖
- 把操作添加到队列中
- 代码实现
/** 下载两张图片并合成 */ -(void)combieDownloadPicture{ __block UIImage *image1; __block UIImage *image2; // 封装下载图片1操作 NSBlockOperation *download1 = [NSBlockOperation blockOperationWithBlock:^{ NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://pic14.nipic.com/20110522/7411759_164157418126_2.jpg"]]; image1 = [UIImage imageWithData:data]; }]; // 封装下载图片2操作 NSBlockOperation *download2 = [NSBlockOperation blockOperationWithBlock:^{ NSData *data = [NSData dataWithContentsOfURL:[NSURL URLWithString:@"http://pic28.nipic.com/20130402/9252150_190139450381_2.jpg"]]; image2 = [UIImage imageWithData:data]; }]; // 封装合成图片操作 NSBlockOperation *combie = [NSBlockOperation blockOperationWithBlock:^{ // 获取图形上下文 UIGraphicsBeginImageContext(CGSizeMake(240, 240)); // 画图1 [image1 drawInRect:CGRectMake(0, 0, 240, 120)]; // 画图2 [image2 drawInRect:CGRectMake(0, 120, 240, 120)]; // 生成图片 UIImage *image = UIGraphicsGetImageFromCurrentImageContext(); // 关闭图形上下文 UIGraphicsEndImageContext(); // 回到主线程刷新UI [[NSOperationQueue mainQueue] addOperationWithBlock:^{ self.imageView.image = image; }]; }]; // 创建队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; // 设置依赖 [combie addDependency:download1]; [combie addDependency:download2]; // 把操作添加到队列中 [queue addOperation:download1]; [queue addOperation:download2]; [queue addOperation:combie];
- 思路
}
```