1、NSoperation是基于GCD封装的
代码语言:javascript复制dispatch_async(_Queue, ^{ //请求数据
NSData *data = [NSData dataWithContentURL:[NSURL URLWithString:@"http://domain.com/a.png"]];
dispatch_async(dispatch_get_main_queue(), ^{ [self refreshViews:data]; });});
有个致命的问题:这个任务是无法取消的 dataWithContentURL:是同步的拉取数据,它会一直阻塞线程直到完成请求,如果是遇到了超时的情况,它在这个时间内会一直占有这个线程;在这个期间并发队列就需要为其他任务新建线程,这样可能导致性能下降等问题。
2、NSOperationQueue相对于GCD来说有以下优点:
- 提供了在 GCD 中不那么容易复制的有用特性。
- 可以很方便的取消一个NSOperation的执行
- 可以更容易的添加任务的依赖关系
- 提供了任务的状态:isExecuteing, isFinished.
NSOperationQueue 有两种不同类型的队列:主队列和自定义队列。主队列运行在主线程之上,而自定义队列在后台执行。在两种类型中,这些队列所处理的任务都使用 NSOperation 的子类来表述。
我们可以通过设置 maxConcurrentOperationCount 属性来控制并发任务的数量,当设置为 1 时, 那么它就是一个串行队列。主对列默认是串行队列,这一点和 dispatch_queue_t 是相似的。
Operation 对象默认按同步方式执行,也就是在调用 start 方法的那 个线程中直接执行。
3、用法
NSOperation实现
一个是直接使用NSInvocationOperation、NSBlockOperation两个子类,一个是自己实现NSOperation的子类
代码语言:javascript复制NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc]initWithTarget:selfselector:@selector(invocationOperationAction)object:nil];
代码语言:javascript复制NSBlockOperation*blockOperation = [NSBlockOperationblockOperationWithBlock:^{
}];
执行任务有两种方法:
- start :方法时与主线程同步,有阻塞主线程的情况,
- 提交到NSOperationQueue中:与主线程是异步,不会阻塞到主线程。NSOperationQueue可以通过maxConcurrentOperationCount设置线程最大并行数量,为1的时候相当于串行,大于1时为并发。
代码语言:javascript复制取消任务
//取消队列中的所有operation
[queue cancelAllOperations];
//取消单个
[blockOperation cancel];
代码语言:javascript复制暂停和恢复
[queue setSuspended:YES];
挂起一个 queue 不会导致正在执行的 Operation 在任务中途暂停,只是简单地阻止调度新 Operation 执行,也就是只是暂停等待中的任务。你 可以在响应用户请求时,挂起一个 queue,来暂停等待中的任务。稍后 根据用户的请求,可以再次调用 setSuspended: 方法继续 Queue 中操作 的执行。
代码语言:javascript复制任务依赖:
[operationB addDependency:operationA]; // 操作B依赖于操作A
自定义Operation
A:使用 main 方法非常简单,开发者不需要管理一些状态属性(例如 isExecuting 和 isFinished),当 main 方法返回的时候,这个 operation 就结束了。这种方式使用起来非常简单,但是灵活性相对重写 start 来说要少一些, 因为main方法执行完就认为operation结束了,所以一般可以用来执行同步任务。
B:如果你希望拥有更多的控制权,或者想在一个操作中可以执行异步任务,那么就重写 start 方法, 但是注意:这种情况下,你必须手动管理操作的状态, 只有当发送 isFinished 的 KVO 消息时,才认为是 operation 结束
当实现了start方法时,默认会执行start方法,而不执行main方法
为了让操作队列能够捕获到操作的改变,需要将状态的属性以配合 KVO 的方式进行实现。如果你不使用它们默认的 setter 来进行设置的话,你就需要在合适的时候发送合适的 KVO 消息。
需要手动管理的状态有:
- isExecuting 代表任务正在执行中
- isFinished 代表任务已经执行完成
- isCancelled 代表任务已经取消执行