NSOperation Class Reference(翻译)

概述

NSOperation是一个用来封装单个任务操作的抽象类。由于它是抽象类,所以你不能直接使用它,而是要通过使用它的自定义子类或者使用系统给提供的两个子类(NSInvocationOperation or NSBlockOperation) 去实现实际的操作。虽然NSOperation是一个抽象类,但是它内部是有很好的逻辑的,它内置的逻辑能让我们更好的关注在业务的层面,不用去太多关注它的实现。

一个operation的对象是一个小得代码对象,它会被执行一次,并且再也不能被执行了(实例使用的一次性)。你经常性的操作是把一个operation的对象添加到一个operation queue中去,operation queue执行这个操作是在在这个队列的另外的线程里面,或者是直接使用系统的libdispatch库。更多的知识关于operation queue可以参考 NSOperationQueue Class Reference.

如果你不想使用operation queue,你可以直接调用你的operation通过是用start实例方法,执行这些个operation并不会给代码添加更多的负担,应为start的方法并非是准备触发的期望。isReady方法汇报这个operation的准备状态。

Opearation Dependencies(操作依赖)

依赖是一种比较方便的方法给队列添加上特殊的操作顺序。你可以通过是用addDependency: 和 removeDependency: 来实现operation的添加依赖。默认的情况下,一个operation对象并不会去考虑知道依赖关系知道它执行完毕。一旦最后的依赖operation完成了,这个时候,operation就开始准备执行了。

NSoperation所支持的依赖并不会去区分关于operation的操作成功或者失败。换句话说,就是哪怕使用cancel的操作,依赖关系也会以为是operation完成了。如果你想区分这些个操作时候依赖operation的成功与否,就需要组合一些而外的的标记或者记录去在你的operation中。

KVO-Compliant Properies(KVO兼容的变量)

NSoperation是KVC和KVO兼容很多变量的类,你可以通过观察者模式去控制这些变量:

isCancelled - read-only property

isConcurrent - read-only property

isExecuting - read-only property

isFinished - read-only property

isReady - read-only property

dependencies - read-only property

queuePriority - readable and writable property

completionBlock - readable and writable property

Multicore Considerations多核注意事项

NSOpearation本身是支持多核的,因此他是线程安全的。可以在不同线程在不用加锁的情况下调用NSOpearation类的方法,因为NSOpearation本身是运行在各个独立的线程里面的。

当你子类化NSOpearation的时候,你必须确认你所重载的的方法在多线程下依然是安全的。如果你的实现方法需要访问数据,你必须确保这些个方法也是线程安全的。所以访问同步访问数据的时候要去避免潜在的数据腐败,更多的信息关于同步访问,请看 Threading Programming Guide

Concurrent Versus Non-Concurrent Operations(并发与非并发的Operations)

如果你想手动执行Operations对象,而且不把这个Operations添加到队列里面去,那你可以设计这个Operations执行的时候是并打的还是非并发。Operations对象默认是非并发的,在非并发的Operations对象,Operations的操作都是同步执行的,也就是说,这个Operations并不去创造一个区分的线程去执行这个任务(也就是说,一般都是单线程的),所以当你调用start的操作的时候,非并发的Operations直接在当前的线程执行。

相比较而言,同步并发执行的Operations,换句话说,当你使用start方法开始一个并发的Operations,这个方法有可能在对应的Operations操作完之前就返回值,主要是因为operation对象创造一个新的线程去执行任务或者因为operation正在执行,当这个控制返回给caller,仅仅这个operation应该继续运行。

如果你经常是用queue去执行自己的operation,那么这种简单的操作是非并发的。如果你想手动执行这些operation,你需要定义你的operation对象像并发的那样,确认他们执行是异步的。定义一个并发的operation需要很多的工作去做,因为你必须通过KVO的通知去管理不断更新的operation的状态和回报他们的变化。当你想确保手动的执行operation不会被执行线程屏蔽,使用并发是个比较好的办法。

Subclassing Notes(子类说明)

NSOperation类提供了,基本的逻辑标记operation执行的状态,但是有些是需要你在真实的场景中去应用的。你怎么去创建NSOperation的子类,取决于你设计这个operation是执行并发或者是非并发的。

Method to Override(重载的方法)

对于非并发的operation来说,你需要重载的仅仅是:

main方法

在这个方法里面,你放置需要执行任务的代码。当然,你也需要定义初始化方法能让你更方便的获取自定义class的实例。你可能需要去定义setter和getter方法从operation中去访问这些个数据。然而,如果你自己定义了这样的setter和getter方法,你需要确认这些方法在多个线程访问的时候是安全的。

如果你生成并发的operation,你需要至少需要去重载这些方法:

start

isConcurrent

isExecuting

isFinished

在并发的operation中,你使用start方法,这代表你将要在异步的情况下启动这个operation。不管你是生成一个线程还是调用异步的方法,你都是要使用start方法的。在你条用start的这个方法的时候,你的isExecuting方法的状态将会改变。这种改变是通过KVO的消息机制实现的,你的isExecuting方法必须是线程安全的返回状态。

当你完成或者取消operation的任务时,你并发的operation对象将会通知isExecuting和isFinished的keypath去改变他们的的状态。(为了应对取消的操作,改变isFinished的状态,即便操作没有完成,也必须汇报它的状态是完成的)。重载isExecuting和isFinished需要很精准的返回当前operation的状态。

对于并打的operation,实际上还有比上面说的更多的方法要去实现。如果给operation添加了依赖,你必须爱要重载额外的方法和提供额外的KVO通知。为了应对依赖,你需要使用isReady的key path。因为dependencies属性管理着operation间的以来操作。

Responding to the Cancel Command(应对取消的要求)

一旦你把operation添加到队列,这个operation你就对他失去控制了。queue会接管你的控制权。当你想要取消这个operation的操作时,该怎么办呢,这个时候为了不让operation进去到CPU的开销里面,可以使用cancel方法或者使用 cancelAllOperations去取消整个队列的操作。

取消一个operation,并非是立即强制这个operation停止工作的。你的取消的状态isCancelled是从程序里面的方法里面来得,所以你需要在取消的时候,确认所有的操作都是正常的,举个例子来说,当这个operation的start的方法还没有被调用,这个start将会退出,在没有任何的操作之前。

你需要一直的去注意cancel的使用

You should always support cancellation semantics in any custom code you write. In particular, your main task code should periodically check the value of theisCancelled method. If the method ever returns YES, your operation object should clean up and exit as quickly as possible. If you implement a customstart method, that method should include early checks for cancellation and behave appropriately. Your custom start method must be prepared to handle this type of early cancellation.

In addition to simply exiting when an operation is cancelled, it is also important that you move a cancelled operation to the appropriate final state. Specifically, if you manage the values for the isFinished and isExecuting properties yourself (perhaps because you are implementing a concurrent operation), you must update those variables accordingly. Specifically, you must change the value returned by isFinished to YES and the value returned by isExecuting to NO. You must make these changes even if the operation was cancelled before it started executing.

Task(接口)

 要注意的是:

Blocks execution of the current thread until the receiver finishes.

屏蔽执行直到当前的线程操作完成

- (void)waitUntilFinished
 
通常是不会被使用的,而且应该避免被使用。使用它可以导致死锁。经典的应用情景是,当你先弄了一个operation,operation在执行,当你想把operation添加到queue中去,你就需要等到这个operation完成它的执行。
posted @ 2014-04-19 23:51  三江汇流  阅读(66)  评论(0)    收藏  举报