IOS 并发编程之NSOperation的使用

理解NSOperation的并发与状态通知机制
本文深入探讨了NSOperation类在并发执行任务时的状态管理与通知机制,包括同步与异步执行的区别,任务状态(等待、就绪、执行中、执行完毕)的跟踪与通知,以及如何通过依赖关系确保任务顺序执行。同时介绍了如何子化NSOperation类以满足特定需求,以及如何处理取消操作。

NSOperation 支持同步和异步执行任务,个人觉得当同步执行任务时其实并不能很好的反应出NSOperation类的设计架构,他的设计重点是考虑到他在异步执行时的一 些情况。说白了,由于异步执行是在其他线程中执行任务,主线程或者其他线程可能想要了解该任务的执行状态(等待、就绪、执行中、执行完毕)等信息,从而根 据该信息做一些相应的处理(而同步执行就不存在这情况)。为了满足该需求,NSOperation类就有必要在该任务进行状态切换时及时的通告外界那些想要知道当前状态信息的对象。 这里要说明一下的是,因为一个NSOperation对象被设计成只执行一次任务,任务执行完成就不能重新再执行,所以即使不需要和外界交流,在NSOperation自身内部也必须维护好当前的状态。
为了满足以上需求,NSOperation以通知(KVO)的方式来告知感兴趣的对象当前operation对象的状态信息,其实NSOperation存在的意义个人认为大致有两点,其一就是为我们定义传播特定信息的特定通知方式,也就是交流的方式像"协议"一样被规定了;第二点就是在第一点的基础上所做的扩展,详细在下文描述。NSOperationQueue就是遵守了NSOperation定义的"协议"才能和NSOperation的其他系统定义的子类交流的,因此如果你想要自己子化NSOperation后的子类能够有效地被加入到NSOperationQueue,那么千万要遵守NSOperation中的“协议”。
说了这么多抽象的 “东东”下面我就来详细说明一下上述的“协议"究竟是怎么规定的。首先NSOperation像外界宣称如果要我执行任务,那么就调用我的start方法(for concurrent)或者main方法(for non_current);如果我的任务开始执行了我通知外界的keyPath是”isExecuting“,如果某个感兴趣的对象注册了这个通知,那么他在收到该通知的时候就可以通过掉用NSOperation的isExecuting方法来验证到底是不是真的已经开始执行了;如果我的任务中途被取消了或者执行完成了,那么我通知外界的keyPath是“isFinished”,如果某个感兴趣的对象注册了这个通知,那么他在收到该通知的时候就可以通过掉用NSOperation的isFinished方法来验证到底是不是真的已经开始执行了。
这里针对上一段”协议”的规定描述下子类化NSOperation的时候应该为 遵循该协议而做的:首先你的任务入口应该写在start方法中,在start方法异步执行任务前要判断目前自己的状态是不是已经停止,如果是,那么就应该通过调用[self didChangeValueForKey:@"isFinished"]来发出通知 ,通知外界,当感兴趣的对象收到通知后可能调用NSOperation的isFinished方法验证是否真的开始了,所以你在子类化的时候要重载该isFinished方法,并且根据你在NSOperation类对象内部的真实状态返回;如果当前状态是已经准备好执行任务了,那么在start调用异步执行任务后就应该通过调用[self didChangeValueForKey:@"isExecuting"]来发出通知 ,通知外界,当感兴趣的对象收到通知后可能调用NSOperation的isExecuting方法验证是否真的开始了,所以你在子类化的时候要重载该isExecuting方法,并且根据你在NSOperation类对象内部的真实状态返回。
从上述可以看出NSoperation的作用除了并发执行任务外,还有就是通过向外界提供各种状态的信息来协助外界完成相应的工作。下面就介绍NSOperation的对象之间是如何相互协助来完成各个NSOperation对象顺序执行的。大概的效果是这样的:当各个NSOperation对象被加入到NSOperationQueue执行后如果被依赖的NSOperation对象没有完成,那么依赖的NSOperation对象就不能开始执行任务。NSOperation类提供了addDenpendency方法来建立相互之间的依赖关系,其实addDenpendency方法内部的实现应该也是按照keyPath为“isFinished”来注册通知,当被依赖的NSoperation对象执行完成后,该依赖的NSOperation对象就收到该通知,从而转入就绪状态。当然如果该NSOperation依赖多个其他的NSOperation对象,那么他就必须通过判断他的denpendencies属性来查看所有被依赖的对象,只有denpendencies中所有对象都为完成状态才转入就绪状态准备执行。当这些NSOperation对象事先已经被加入NSOperationQueue队列中时,准备就绪的对象就马上能被NSoperationQueue对象调用转入执行状态。
从上面一段不难发现,NSOperation通知外界自己已经进入就绪状态的决定是通过对denpendencies属性中的所有对象的状态判断来做出的。其实他每每收到他依赖的对象的完成通知时都回去判断denpendencies属性中的对象是不是全部都执行完了,只有全部都执行完了,他才会通过keyPath为“isReady”通知外界自己已经进入就绪状态,默认的isReady方法的实现也是根据判断依赖的对象是不是都已经完成了从而返回YES或者NO。因此,如果你子类化的NSOperation类要依赖于不是NSOperation对象的东西,也就是说除了对denpendencies中对象状态的判断,你还要根据其他信息来进一步判断目前能不能进入就绪状态,如果在该判断方法中断定能够进入就绪状态 ,那么你就可以用某个属性设置当前为就绪状态并且你必须要以keyPath为“isReady”通知外界,外界收到通知时可以调用isReady方法验证,所以你必须重载isReady方法,对你重载的建议引用官方文档上的一句话就是: your custom implementation should invoke super and incorporate its return value into the readiness state of the object.

最后要提及的是关于取消NSoperation操作的问题,默认的实现是如果一个NSOperation被取消,那么他还可以再次被执行,如果你把该NSOperation事先放入NSOperationQueue中,然后在他执行的时候取消,那么该NSOperation实际上还是保留在队列中的,只有处于完成状态的时候,队列才会清除该NSOperation对象。所以加入你想实现一个NSOperation子类,当调用他的cancel方法后该类型的对象就不能再执行了,那么你必须重载cancel方法,使得执行完cancel后把该对象的状态变为完成状态,并且通知外界该对象状态已经改变,当外界调用isCancel方法时便可以发现该对象的已经进入完成状态,这时如果是NSOperationQueue,那么他会把该NSOperation对象从队列中移除。

转载于:https://www.cnblogs.com/wangxia0/archive/2013/03/28/2987104.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值