NSOperationQueue&NSOperation
NSOperationQueue
有两种不同类型的队列:主队列和自定义队列。主队列运行在主线程之上,而自定义队列在后台执行。在两种类型中,这些队列所处理的任务都使用NSOperation
的子类来表述。
NSOperationQueue *mainQueue = [NSOperationQueue mainQueue]; //主队列 NSOperationQueue *queue = [[NSOperationQueue alloc] init]; //自定义队列 NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
//任务执行
}];
[queue addOperation:operation];
我们可以通过设置 maxConcurrentOperationCount
属性来控制并发任务的数量,当设置为 1时, 那么它就是一个串行队列。主对列默认是串行队列,这一点和 dispatch_queue_t 是相似的。
NSOperation
你可以使用系统提供的一些现成的NSOperation的子类, 如 NSBlockOperation、NSInvocationOperation等(如上例子)。你也可以实现自己的子类, 通过重写 main
或者start方法 来定义自己的 operations 。使用 main方法非常简单,开发者不需要管理一些状态属性(例如 isExecuting 和 isFinished),当 main 方法返回的时候,这个 operation 就结束了。这种方式使用起来非常简单,但是灵活性相对重写 start 来说要少一些, 因为main方法执行完就认为operation结束了,所以一般可以用来执行同步任务。
@implementation YourOperation
- (void)main{
// 任务代码 ...
}
@end
如果你希望拥有更多的控制权,或者想在一个操作中可以执行异步任务,那么就重写 start方法, 但是注意:这种情况下,你必须手动管理操作的状态, 只有当发送 isFinished的 KVO 消息时,才认为是 operation 结束。
@implementation YourOperation - (void)start{
self.isExecuting = YES;
// 任务代码 ...
} - (void)finish //异步回调
{
self.isExecuting = NO;
self.isFinished = YES;
}
@end
当实现了start方法时,默认会执行start方法,而不执行main方法。为了让操作队列能够捕获到操作的改变,需要将状态的属性以配合 KVO的方式进行实现。如果你不使用它们默认的 setter 来进行设置的话你就需要在合适的时候发送合适的 KVO消息。
需要手动管理的状态有:
isExecuting代表任务正在执行中
isFinished代表任务已经执行完成
isCancelled代表任务已经取消执行手动的发送 KVO消息, 通知状态更改如下 :
[self willChangeValueForKey:@"isCancelled"];
_isCancelled = YES;
[self didChangeValueForKey:@"isCancelled"];
为了能使用操作队列所提供的取消功能,你需要在长时间操作中时不时地检查 isCancelled属性, 比如在一个长的循环中:
@implementation MyOperation
- (void)main{
while (notDone && !self.isCancelled)
{
// 任务处理
}
}
@end