最近在项目中负责一个下载模块,使用的是NSOperation+NSOperationQueue实现的,以前总以为自己对NSOperation已经很熟悉了,也写过很多Demo,但是到真正使用的时候,才发现里面还有很多细节的东西自己没有注意到,这篇博客算是对NSOperation的用法的一个总结。比较简单的NSBlockOperation以及NSInvocationOperation就不介绍,本文主要讲解一下自定义NSOperation的方法以及注意事项。
很多技术Blog在介绍自定NSOperation时,思路都是大同小异,大致可以分为一下几步:
- 创建一个集成自NSOperation的类
- 重写NSOperation的main()方法,在main()方法中实现耗时操作
- 然后使用时创建自定义的NNSOperation对象,把它添加到NSOperationQueue中,这样就可以自动执行了
其实,这只是自定义NSOperation的一种方法,而且是比较简单的一种方法,不需要自己去控制NSOperation的完成,取消等。另外一种方式是重写NSOperation的start方法,这种方法就需要你自己去控制NSOperation的完成,取消,执行等,而且有许多需要注意的地方。下面着重介绍一些第二种方法。
废话不多说,直接上代码:
1 |
|
上述代码创建了一个NSOperation的子类CustomOperation,然后重写了start方法,在start方法中模拟了一个耗时操作,然后在main方法中创建一个NSOperationQueue并添加三个CustomOperation,执行结果是只有op1被执行,op2和op3一直没有被执行。这是因为,一个NSOperationQueue在判断一个Operation是否执行完成的标志是Operation的- (BOOL)isFinished
方法返回YES,所以这里需要有一个变量来记录当前Operation执行的状态,修改代码,如下:
1 |
|
这里先定义个一个表示Operation状态的枚举,共有三种状态:
- OperationStateReady:准备状态,创建Operation后默认就是准备状态
- OperationStateExecuting:执行状态,Operation在执行过程中的状态
- OperationStateFinished:完成状态,Operation执行完成后的状态
然后在main方法中先将状态置为执行状态,然后在耗时操作执行完后,将状态置为完成状态。有了状态之后,重写NSOperation的- (BOOL)isFinished
方法,当状态为OperationStateFinished时返回YES,否则返回NO。这样,NSOperationQueue就可以知道操作已经执行完成。运行代码,现在三个Operation就可以按顺序执行了。
继续完善代码
1 | @implementation CustomOperation |
这样,一个重写start方法的自定义NSOperation就完成了,这是CustomOperation支持Cancel操作,测试代码如下:
1 | int main(int argc, const char * argv[]) { |
运行代码,会发现只执行了op1和op2,达到了我们预期的效果。
这就是一个完整的自定义NSOperation的方法,这里的关键点就是那几个状态。
比较一下重写start函数的方法和重写main函数的方法,重写main函数实现起来更加简单,不需要自己控制Operation的状态,但是重写start函数更加灵活,可以根据自己的需求定制不同的状态。更加完善的实现可以参看AFNetworking的AFURLConnectionOperation实现,里面有很多值得学习的东西。
参考资料:
NSOperation