多线程编程 - NSOperation
来源:互联网 发布:肿瘤的临床数据分析 编辑:程序博客网 时间:2024/06/06 14:03
多线程编程 - NSOperation
一、NSOperation
- 简介
在iOS开发中,为了提升用户体验,我们通常会将操作耗时的操作放在主线程之外的线程进行处理。对于正常的简单操作,我们更多的是选择代码更少的GCD,让我们专注于自己的业务逻辑开发。NSOperation在ios4后也基于GCD实现,但是相对于GCD来说可控性更强,并且可以加入操作依赖。
NSOperation实例封装了需要执行的操作和执行操作所需的数据,并且能够以并发或非并发的方式执行这个操作。
NSOperation本身是抽象基类,因此必须使用它的子类,使用NSOperation子类的方式有2种:
1> Foundation框架提供了两个具体子类直接供我们使用:NSInvocationOperation和NSBlockOperation
2> 自定义子类继承NSOperation,实现内部相应的方法
- 执行操作
NSOperation调用start方法即可开始执行操作,NSOperation对象默认按同步方式执行,也就是在调用start方法的那个线程中直接执行。NSOperation对象的isConcurrent方法会告诉我们这个操作相对于调用start方法的线程,是同步还是异步执行。isConcurrent方法默认返回NO,表示操作与调用线程同步执行 - 取消操作与挂起操作
operation开始执行之后, 默认会一直执行操作直到完成,我们也可以调用cancel方法中途取消操作
[operation cancel];// 取消queue中所有的操作[self.queue cancelAllOperations];//将挂起状态取消self.queue.suspended = NO;
- 监听操作的执行
如果我们想在一个NSOperation执行完毕后做一些事情,就调用NSOperation的setCompletionBlock方法来设置想做的事情
// 如果我们想在一个NSOperation执行完毕后做一些事情,就调用NSOperation的setCompletionBlock方法来设置想做的事情[op setCompletionBlock:^{ NSLog(@"完成");}];//或// op.completionBlock = ^(){// NSLog(@"完成");// };
二、NSInvocationOperation
简介
基于一个对象和selector来创建操作。如果你已经有现有的方法来执行需要的任务,就可以使用这个类创建并执行操作
// 基于一个对象和selector来创建操作。如果你已经有现有的方法来执行需要的任务,就可以使用这个类 NSInvocationOperation * op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downImage) object:nil]; // 一个NSOperation对象可以通过调用start方法来执行任务,默认是同步执行的。 [op start];
三、NSBlockOperation
简介
能够并发地执行一个或多个block对象,所有相关的block都执行完之后,操作才算完成创建并执行操作
// 能够并发地执行一个或多个block对象,所有相关的block都执行完之后,操作才算完成 NSBlockOperation * op = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"%@",[NSThread currentThread]); NSLog(@"第一个操作"); }]; [op start];
- 添加操作
// 通过addExecutionBlock方法添加block操作,开启多个线程 [op addExecutionBlock:^{ NSLog(@"%@",[NSThread currentThread]); NSLog(@"第二个操作"); }]; [op addExecutionBlock:^{ NSLog(@"%@",[NSThread currentThread]); NSLog(@"第三个操作"); }];
这几个block是并发执行的,也就是在不同线程中执行的,num属性可以看成是线程的id
四、NSOperationQueue
NSOperation是基于GCD的,把GCD的block封装成opertion,NSOperationQueue是全局队列封装
将NSOperation添加到一个NSOperationQueue(操作队列)中去执行,而且是异步执行的。
//创建一个操作队列 NSOperationQueue * queue = [[NSOperationQueue alloc] init]; NSInvocationOperation * op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downImage) object:nil]; NSBlockOperation * op2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"op2 - %@",[NSThread currentThread]); }]; // waitUntilFinished yes 操作完成后执行下面的代码 no 先执行下面的代码 //添加一个block形式的operation [queue addOperationWithBlock:^{ NSLog(@"op3 - %@",[NSThread currentThread]); }]; [queue addOperations:@[op,op2] waitUntilFinished:NO];
最大并发数,这个功能NSOperation比较常用
self.queue.maxConcurrentOperationCount = 2;
五、设置依赖关系
NSOperation中我们可以为操作分解为若干个小的任务,通过添加他们之间的依赖关系进行操作,这点在设计上是很有意义的。比如我们最常用的图片异步加载,第一步我们是去通过网络进行加载,第二步我们可能需要对图片进行下处理(调整大小或者压缩保存)。我们可以直接调用- (void)addDependency:(NSOperation*)op;这个方法添加依赖:
self.queue = [[NSOperationQueue alloc] init]; NSInvocationOperation * op1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(downImage) object:nil]; //设置优先级,数据量少看不出 op1.queuePriority = -4; NSBlockOperation * op2 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"解压图片包"); }]; op2.queuePriority = 0; NSBlockOperation * op3 = [NSBlockOperation blockOperationWithBlock:^{ NSLog(@"观看漫画"); }]; op3.queuePriority = 4; //添加NSOperation的依赖对象// [op2 addDependency:op1];// [op3 addDependency:op2]; //注意:不能创建环形依赖,如A依赖B,B依赖A,这是错误的 // [op1 addDependency:op3]; [self.queue addOperations:@[op1,op2,op3] waitUntilFinished:YES];
六、NSOperationxian线程之间的通信
线程之间信,是通过在某个线程中调用另一个线程实现的
[self.queue addOperationWithBlock:^{ NSLog(@"%@",[NSThread currentThread]); NSLog(@"下载图片"); //获取主队列 [[NSOperationQueue mainQueue] addOperationWithBlock:^{ NSLog(@"%@",[NSThread currentThread]); NSLog(@"更新UI"); }]; }];
线程通信案例:两个图片的合并
//创建操作1 NSBlockOperation * download1 = [NSBlockOperation blockOperationWithBlock:^{ NSURL * url = [NSURL URLWithString:@"http://g.hiphotos.baidu.com/lvpics/w=1000/sign=82800ad878cb0a4685228f395b53f724/96dda144ad3459823cc40db00ff431adcbef8442.jpg"]; NSData * data = [NSData dataWithContentsOfURL:url]; image1 = [UIImage imageWithData:data]; NSLog(@"download1- %@",[NSThread currentThread]); }]; __block UIImage * image2; //创建操作2 NSBlockOperation * download2 = [NSBlockOperation blockOperationWithBlock:^{ NSURL * url = [NSURL URLWithString:@"http://f.hiphotos.baidu.com/lvpics/h=800/sign=08f9c974e21190ef1efb9fdffe1a9df7/c8177f3e6709c93dfd03176e9a3df8dcd00054b1.jpg"]; NSData * data = [NSData dataWithContentsOfURL:url]; image2 = [UIImage imageWithData:data]; NSLog(@"download2- %@",[NSThread currentThread]); }]; //创建操作3(用于合并图片) NSBlockOperation * combine = [NSBlockOperation blockOperationWithBlock:^{ //创建位图上下文 UIGraphicsBeginImageContextWithOptions(CGSizeMake(200, 200), NO, 1); //设置显示的位置 [image1 drawInRect:CGRectMake(0, 0, 200, 100)]; [image2 drawInRect:CGRectMake(0, 100, 200, 100)]; //获取当前图片上下文 UIImage * image = UIGraphicsGetImageFromCurrentImageContext(); UIGraphicsEndImageContext(); NSLog(@"combine- %@",[NSThread currentThread]); //返回主线程更新UI [[NSOperationQueue mainQueue] addOperationWithBlock:^{ self.imageView.image = image; NSLog(@"main - %@",[NSThread currentThread]); }]; }]; //设置操作的依赖关系 [combine addDependency:download1]; [combine addDependency:download2]; //向全局队列添加操作 [self.queue addOperations:@[download1,download2,combine] waitUntilFinished:YES];
正确响应取消事件
operation开始执行之后,会一直执行任务直到完成,或者显式地取消操作。取消可能发生在任何时候,甚至在operation执行之前。尽管NSOperation提供了一个方法,让应用取消一个操作,但是识别出取消事件则是我们自己的事情。如果operation直接终止, 可能无法回收所有已分配的内存或资源。因此operation对象需要检测取消事件,并优雅地退出执行
NSOperation对象需要定期地调用isCancelled方法检测操作是否已经被取消,如果返回YES(表示已取消),则立即退出执行。不管是自定义NSOperation子类,还是使用系统提供的两个具体子类,都需要支持取消。isCancelled方法本身非常轻量,可以频繁地调用而不产生大的性能损失
以下地方可能需要调用isCancelled:
- 在执行任何实际的工作之前
- 在循环的每次迭代过程中,如果每个迭代相对较长可能需要调用多次
- 代码中相对比较容易中止操作的任何地方
- 多线程编程2 - NSOperation
- 多线程编程2 - NSOperation
- 多线程编程2-NSOperation
- 多线程编程2 - NSOperation
- 多线程编程 - NSOperation
- 多线程编程2 - NSOperation
- 多线程编程2 - NSOperation
- 多线程编程2 - NSOperation
- 多线程编程2 - NSOperation
- 多线程编程2 - NSOperation
- 多线程编程2 - NSOperation
- 多线程编程2 - NSOperation
- 多线程编程2 - NSOperation
- 多线程编程2 - NSOperation
- 多线程编程2-NSOperation
- 多线程编程2-NSOperation
- [TwistedFate]多线程编程NSOperation
- 多线程编程--NSOperation
- sgi stl linux下编译运行
- BSG白山极客挑战赛-B君的圆锥(三分+数学)
- c++作业6
- Python improve performance
- 单链表按k值重新排序
- 多线程编程 - NSOperation
- java 数字的进制转换
- malloc()函数的实现原理和工作机制!!!!!!!
- [Android自定义View] 计算View尺寸方法onMeasure()
- 给大家推荐对Redis分析讲解比较详细的大牛
- yarn内存配置指南
- CSDN博客中插入图片的办法
- 类模板的写法
- 深入理解java异常处理机制