接上一篇
2、NSOperation
NSOperation是一个抽象类,本身并没有办法去直接使用,如果我们要使用它,就要去使用它的子类。IOS已经给我们提供了两个已经实现好的子类,NSInvocationOperation和NSBlockOperation。
对于这两个子类虽然IOS本身提供了start方法,不过我们一般不去直接使用它而需要借助另外一个类 NSOperationQueue 。
NSOperationQueue顾名思义是一个操作队列,他会给我们提供一个有序的执行队列,看一下苹果官方对这个类的描述
The NSOperationQueue class regulates the execution of a set of NSOperation objects. After being added to a queue, an operation remains in that queue until it is explicitly canceled or finishes executing its task. Operations within the queue (but not yet executing) are themselves organized according to priority levels and inter-operation object dependencies and are executed accordingly. An application may create multiple operation queues and submit operations to any of them.
Inter-operation dependencies provide an absolute execution order for operations, even if those operations are located in different operation queues. An operation object is not considered ready to execute until all of its dependent operations have finished executing. For operations that are ready to execute, the operation queue always executes the one with the highest priority relative to the other ready operations. For details on how to set priority levels and dependencies, see NSOperation Class Reference.
You cannot directly remove an operation from a queue after it has been added. An operation remains in its queue until it reports that it is finished with its task. Finishing its task does not necessarily mean that the operation performed that task to completion. An operation can also be canceled. Canceling an operation object leaves the object in the queue but notifies the object that it should abort its task as quickly as possible. For currently executing operations, this means that the operation object’s work code must check the cancellation state, stop what it is doing, and mark itself as finished. For operations that are queued but not yet executing, the queue must still call the operation object’s start method so that it can processes the cancellation event and mark itself as finished.
大概意思是 NSOperationQueue类调节一组的NSOperation对象的执行。在队列中的NSOperation对象会按照绝对的顺序去执行,也就是说当任务加入到任务队列后,会自动按照优先级和依赖关系自动运行。
还是上面的例子
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
// NSThread *mThread = [[NSThread alloc] initWithTarget:self selector:@selector(DownImage:) object:IMAGE_PATH];
// [mThread start];
NSInvocationOperation *mOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(DownImage:) object:IMAGE_PATH];
// [mOperation start];
NSOperationQueue *mQueue = [[NSOperationQueue alloc] init];
[mQueue addOperation:mOperation];
}
看上去很简单,仅仅就是创建任务,然后加入到队列。这个队列是个任务的pool,遵循生产者-消费者的关系,当有任务的时候会自动运行任务。我们可以使用setMaxConcurrentOperationCount:这个方法来设置这个queue里面的线程总数,默认值是-1,意思是没有限制。
在继承NSOperation后,对于非并发的工作,需要实现NSOperation子类的main方法:
-(void)main
{
@try
{
// 处理工作任务
}
@catch(…)
{
// 处理异常,但是不能再重新抛出异常
}
}
因为NSOperation的任务是可以cancel的,所以在main方法处理任务时就要不断轮询isCancelled。另外,这个main方法本来是空的,所以不需要调用[super main]这句。
还有一个start方法,这个start方法是工作的入口,通常是用来设置线程需要的运行环境的。和main一样,不要调用[super start]。这个方法还会区分这个运行的状态,如果是canceled或者已经结束了,这个任务就不会运行;而如果是正在运行或者还没ready,则会扔出一个异常。
如果要支持并发任务,至少需要重写start、isConcurrent、isExecuting、isFinished四个方法。这里需要说一下这个isConcurrent方法,这个方法是标志operation是否并行执行的,如果是concurrent的,则返回YES;反之,则返回NO。如果没有重写这个方法,则默认NO,但在OS X10.6之后,这个值被忽略了。
另外,NSOperation的一些属性是支持KVC的,我们可以通过KVO方法来观察这些属性并在应用的其他地方来控制程序运行,所以需要在合适的时候发出KVO通知。
NSOperation支持的KVO属性有:isCancelled、isConcurrent、isExecuting、isFinished、isReady、dependencies、queuePriority、completionBlock。如果你增加了属性,推荐同样支持KVC和KVO。