• NSOperation


    28 July 2013

    几乎每个开发者都知道,让App快速响应的秘诀是把耗时的计算丢到后台线异步去做。于是,Modern Objective-C开发者有两个选择:GCDNSOperation.

    由于GCD已经发展的比较主流了,我们稍后再说它,先说说面向对象的NSOperation.

    NSOperation表示一个单独的计算单元,它是一个抽象类(很类似Java里的Runnable接口),给子类提供了一些非常有用且线程安全的特性,比如状态(state),优先级(priority),依赖(dependencies)以及取消(cancellation). 如果你不想子类化NSOperation,可以选择使用NSBlockOperation这个NSOperation的子类,它可以把一个block包装成为一个NSOperation.

    非常适合使用NSOperation的任务例子包括network requests, 图片的缩放,语言处理或者其他一些重复的、结构化的以及需要运行较长时间来处理数据的任务。

    但是,仅仅把计算包装成一个对象,没有一些监管也不会非常的有用,这时NSOperationQueue就出现了。

    NSOperationQueue控制各个operation的并发执行.它像是一个优先级队列,operation大致的会按FIFO的方式被执行,不过带有高优先级的会跳到低优先级前面被执行(用NSOperation的queuePriority方法来设置优先级)。 NSOperationQueue支持并发的执行operations,通过maxConcurrentOperationCount来指定最大并发数,就是同时有最多有多少个operation同时被运行。

    可以通过调用-start方法来启动一个NSOperation,或者把它放到NSOperationQueue里,当到达队列最前端时也会被自动的执行。

    现在来看看NSOperation的几个不同的特性,以及如何如果使用和子类化它:

    状态 State

    NSOperation构建了一个非常优雅的状态机来描述一个operation的执行过程:

    isReady -> isExecuting -> isFinished

    State是通过这些keypath的KVO通知来隐式的得到,而不是显式的通过一个state的属性。就是说,当一个operation已经准备就绪,将要被执行时,它会为isReadykeyPath发送一个KVO的通知,对应的属性值也会变为YES.

    为了构造一致的状态,下面每个属性都与其他属性相互排斥:

    • isReady: 如果operation已经做好了执行的准备返回YES,如果它所依赖的操作存在一些未完成的初始化步骤则返回NO。
    • isExecuting:如果operation正在执行它的任务返回YES,否则返回NO。
    • isFinished: 任务成功的完成了执行,或者中途被Cancel,返回YES。NSOperationQueue只会把isFinished为YES的operation踢出队列,isFinished为NO的永远不会被移除,所以实现时一定要保证其正确性,避免死锁的情况发生。

    取消 Cancellation

    如果正在进行的operation所做的工作不再有意义,尽早的取消掉是非常有必要的。取消一个operation可以是显式的调用cancel方法,也可以是operation依赖的其他operation执行失败。

    和state类似,当NSOperation的被取消,是通过isCancelledkeypath的KVO来获得。当NSOperation的子类覆写cancel方法时,注意清理掉内部分配的资源。特别注意的是,这时isCancelled和isFinished的值都变为了YES,isExecuting为值变为NO。

    一个需要格外注意的地方是和单词“cancel”有关的两个词:

    • cancel : 带一个”l” 表示方法 (动词)
    • isCancelled : 带两个”l”表示属性(形容词)

    优先级 Priority

    所有的operation在NSOperationQueue中未必都是一样的重要,设置queuePriority属性就可以提升和降低operation的优先级,queuePriority属性可选的值如下:

    • NSOperationQueuePriorityVeryHigh
    • NSOperationQueuePriorityHigh
    • NSOperationQueuePriorityNormal
    • NSOperationQueuePriorityLow
    • NSOperationQueuePriorityVeryLow

    另外,operation可以指定一个threadPriority值,它的取值范围是0.0到1.0,1.0代表最高的优先级。queuePriority决定执行顺序的优先级,threadPriority决定当operation开始执行之后分配的计算资源的多少。

    依赖 Dependencies

    取决于你的App的复杂性,可能会需要把一个大的任务分成多个子任务,这时NSOperation依赖就排上用场了。

    比如从服务器上下载和缩放图片的过程,你可能会想把下载图片作为一个operation,缩放作为另外一个(这样也可以复用下载图片和缩放图片的代码)。然后,一个图片在从服务器上下载下来之前是没有办法缩放的,于是我们说缩放图片的operation依赖从服务器上下载图片的operation,后者必须先完成,前者才能开始执行。用代码表示是这样的:

    [resizingOperation addDependency:networkingOperation];
    [operationQueue addOperation:networkingOperation];
    [operationQueue addOperation:resizingOperation];
    

    一个operation只有在它依赖的所有的operation的isFinished都为YES的时候才会开始执行。要记住添加到queue里的所有的operation的依赖关系,并避免循环依赖,比如A依赖B,B依赖A,这样会产生死锁。

    completionBlock

    completionBlock是在iOS4和Snow Leopard中添加的一个非常有用的特性。当一个NSOperation完成之后,就会精确地只执行一次completionBlock。我们需要在operation完成之后想做点什么的时候这个属性就会非常有用。比如当一个网络请求结束之后,可以在completionBlock里处理返回的数据。

    总结

    NSOperation依然是Modern Objective-C程序员杀手锏里的重要工具。相对于GCD非常适用于in-line的异步处理,NSOperation提供了更综合的、面向对象的计算模型,非常适用于封装结构化的数据,重复性的任务。把它加到你的下个项目中,给你的用户和你自己都带来乐趣吧!

    译者注

    本文编译自NSHipster里的NSOperation一文,感谢作者Mattt Thompson, 来头很大,这是他的简介:

    Mattt Thompson is the Mobile Lead at Heroku, and the creator & maintainer of AFNetworking and other popular open-source projects, including Postgres.app & Induction. He also writes about obscure & overlooked parts of Cocoa on NSHipster.

    最上面的图片是来自于WWDC2013中的“Hidden Gems in Cocoa and Cocoa Touch”(228)中Mattt讲NSOperation时的截图,这个视频一共有30个tips,这是第8个tip,大部分的内容我是第一次知道,非常值得看,而且如果有条件的话,建议下载HD版本的视频来看,效果比SD好太多。字幕文件在我的这个repo里, :)

    如有文中有不准确的地方,欢迎留言指正 :)

    Enjoy!

  • 相关阅读:
    JSP第二次作业
    软件测试课堂练习
    内容提供者读取短信信息
    购物车
    第六周jsp
    第四周jsp
    第一周 软件测试
    第八次安卓
    安卓第七次作业
    安卓第六次作业
  • 原文地址:https://www.cnblogs.com/yingkong1987/p/3221479.html
Copyright © 2020-2023  润新知