IOS中常见的Operation —— NSOperation
NSOperation
在应用需要进行异步处理时,我们需要选择一下异步处理的方式,GCD通常是一个不错得选择,但是也许需要更加面向对象的方式,那么就会使用NSOperation队列,队列中需要执行的操作代码放在NSOperation的子类中。子类将操作的数据和待执行的代码封装起来加入到队列中。
NSOperation类是一个抽象类。其两个子类为:NSInvocationOperation和NSBlockOperation。两个子类分别基于selector和block进行工作。一个Operation对象是一个single-shot对象,它只会执行一次并不能再次执行。
NSOperation常用的方法有:
- start 开始操作
- cancel取消操作
- setCompletionBlock:设置操作完成后执行的代码
- setThreadPriority:设置操作的线程优先级
在NSOperation执行前后对应着一些状态:
isCancelled
操作可以取消,但是仅当操作还没执行的时候才可以取消,如果操作已经开始执行,那么取消操作将不会产生效果。
isConcurrent
一个单独的操作默认是不允许并发的,但是你可以重写这个属性的getter方法,让其返回YES。如果你把操作加入到操作队列中,那么在操作队列允许多个最大并发线程的时候,它们则可以并发执行。
isExecuting
是否在执行状态
isFinished
是否完成。当一个操作执行结束后,会对自身标记完成,通过kvo通知属性发生更改,以便调用者来实时的观察操作的状态。
isReady
是否准备好来执行。
下面对NSOperation的使用进行简单的测试。
![](http://images0.cnblogs.com/blog/594870/201402/161435557949226.png)
这时打印的结果为:
2013-11-06 21:59:42.163 NSOperationDemo[446:a0b] isCancelled: 0
2013-11-06 21:59:42.165 NSOperationDemo[446:a0b] isConcurrent: 0
2013-11-06 21:59:42.165 NSOperationDemo[446:a0b] isExecuting: 0
2013-11-06 21:59:42.166 NSOperationDemo[446:a0b] isFinished: 0
2013-11-06 21:59:42.166 NSOperationDemo[446:a0b] isReady: 1
2013-11-06 21:59:42.165 NSOperationDemo[446:a0b] isConcurrent: 0
2013-11-06 21:59:42.165 NSOperationDemo[446:a0b] isExecuting: 0
2013-11-06 21:59:42.166 NSOperationDemo[446:a0b] isFinished: 0
2013-11-06 21:59:42.166 NSOperationDemo[446:a0b] isReady: 1
2013-11-06 21:59:42.166 NSOperationDemo[446:a0b] 5050
2013-11-06 21:59:42.167 NSOperationDemo[446:a0b] isCancelled: 0
2013-11-06 21:59:42.167 NSOperationDemo[446:a0b] isConcurrent: 0
2013-11-06 21:59:42.168 NSOperationDemo[446:a0b] isExecuting: 0
2013-11-06 21:59:42.168 NSOperationDemo[446:a0b] isFinished: 1
2013-11-06 21:59:42.169 NSOperationDemo[446:a0b] isReady: 1
只有isFinished在完成后发生了变化
然后在执行前cancel掉操作
2013-11-06 22:01:25.762 NSOperationDemo[460:a0b] isCancelled: 0
2013-11-06 22:01:25.763 NSOperationDemo[460:a0b] isConcurrent: 0
2013-11-06 22:01:25.763 NSOperationDemo[460:a0b] isExecuting: 0
2013-11-06 22:01:25.764 NSOperationDemo[460:a0b] isFinished: 0
2013-11-06 22:01:25.764 NSOperationDemo[460:a0b] isReady: 1
2013-11-06 22:01:25.763 NSOperationDemo[460:a0b] isConcurrent: 0
2013-11-06 22:01:25.763 NSOperationDemo[460:a0b] isExecuting: 0
2013-11-06 22:01:25.764 NSOperationDemo[460:a0b] isFinished: 0
2013-11-06 22:01:25.764 NSOperationDemo[460:a0b] isReady: 1
2013-11-06 22:01:25.765 NSOperationDemo[460:a0b] isCancelled: 1
2013-11-06 22:01:25.765 NSOperationDemo[460:a0b] isConcurrent: 0
2013-11-06 22:01:25.766 NSOperationDemo[460:a0b] isExecuting: 0
2013-11-06 22:01:25.766 NSOperationDemo[460:a0b] isFinished: 1
2013-11-06 22:01:25.766 NSOperationDemo[460:a0b] isReady: 1
如前面介绍,cancel操作其实并不是直接让操作消失而是将他在执行后立即将自身标记取消,不执行行为代码,并将自身标记为完成。
block操作的创建更加简单,直接在创建对象时将需要执行的代码封包到block中
NSBlockOperation *blockOp = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"i'm block");
}];
[blockOp start];
NSLog(@"i'm block");
}];
[blockOp start];
NSOperationQueue
NSOperationQueue类调节一组NSOperation对象的执行。在被添加到队列后,操作被队列持有,直到操作被明确的取消或者完成了执行的任务。队列中的操作自己根据优先级和互相的依赖关系来组织顺序并依此执行。一个应用程序可以创建多个操作队列,并提交任何操作。
操作间可以建立依赖,例如这段代码:
![](http://images0.cnblogs.com/blog/594870/201402/161436275519192.png)
在没有建立依赖的情况下,打印结果是1与2交替执行,然而如果在加入到队列前先建立依赖关系则结果就会不同。
加入代码[blockOp1 addDependency:blockOp2];
打印结果:
2013-11-06 22:16:47.769 NSOperationDemo[524:1403] i'm block2
2013-11-06 22:16:47.771 NSOperationDemo[524:1403] i'm block2
2013-11-06 22:16:47.771 NSOperationDemo[524:1403] i'm block2
2013-11-06 22:16:47.772 NSOperationDemo[524:1403] i'm block2
2013-11-06 22:16:47.773 NSOperationDemo[524:1403] i'm block2
2013-11-06 22:16:47.773 NSOperationDemo[524:1403] i'm block1
2013-11-06 22:16:47.774 NSOperationDemo[524:1403] i'm block1
2013-11-06 22:16:47.775 NSOperationDemo[524:1403] i'm block1
2013-11-06 22:16:47.776 NSOperationDemo[524:1403] i'm block1
2013-11-06 22:16:47.776 NSOperationDemo[524:1403] i'm block1
2013-11-06 22:16:47.771 NSOperationDemo[524:1403] i'm block2
2013-11-06 22:16:47.771 NSOperationDemo[524:1403] i'm block2
2013-11-06 22:16:47.772 NSOperationDemo[524:1403] i'm block2
2013-11-06 22:16:47.773 NSOperationDemo[524:1403] i'm block2
2013-11-06 22:16:47.773 NSOperationDemo[524:1403] i'm block1
2013-11-06 22:16:47.774 NSOperationDemo[524:1403] i'm block1
2013-11-06 22:16:47.775 NSOperationDemo[524:1403] i'm block1
2013-11-06 22:16:47.776 NSOperationDemo[524:1403] i'm block1
2013-11-06 22:16:47.776 NSOperationDemo[524:1403] i'm block1
只有在op2执行完成后,op1才会执行。如果队列中有多个操作,则队列会按照他们的依赖关系,优先级属性设置情况等安排各个操作的先后关系。
操作间的依赖关系提供了一个绝对的执行顺序给这些操作,哪怕是不同队列的操作也可以建立依赖。操作对象不被视为准备执行直到所有依赖于它的操作执行完毕。对于那些准备执行的操作,操作队列总是执行具有最高优先级的。
不能直接的从队列中删除操作在它被添加到队列之后。操作会被队列持有知道它报告自己已经完成任务。当然,完成任务不一定意味着它真的从头到尾执行了它的代码,也有可能它在还没执行前被cancel掉,被cancel的操作同样会被调用start方法,以便它将自身标记完成后,离开队列。
队列还可以挂起或继续
NSOperationQueue拥有一个isSuspended属性,来表示它是否被挂起。当我们需要临时挂起队列时,可以通过setSuspended:方法来设置是否挂起或继续运行队列。当然,已经在运行的操作在队列被挂起时,并不会暂停。
获取队列中操作的方法可以通过队列的operations属性来拿到操作数组,以便获取操作对其进行取消等行为。
与其他多线程方法的使用相同
我们可以在自己建立的并发操作执行一些代码,在刷新UI时,则需要在主线程队列中执行
获取主线程队列的方法
[NSOperationQueue mainQueue]
调用其addOperationWithBlock:方法来执行刷新界面的相关操作。
其实在多线程的使用上,每个开发者都有着自己的习惯在GCD或者NSOperationQueue都能完成功能的时候。相对来讲,GCD框架更接近底层,而操作队列则是苹果对底层功能更灵活应用的一个封装。
所以,NSOperationQueue的优点在于:
提供了面向对象的接口。
可以设置优先级以及依赖关系调度。
还有一个很重要的就是,能够设置最大的并发数(setMaxConcurrentOperationCount:)。(例如在网络访问时,3G状态下最大同时访问数为2,Wi-Fi则为6)
以上为本篇博客的全部内容,欢迎指正和交流。转载注明出处~