iOS多线程之四:NSOperation的使用

一、NSOperation

NSOperation是苹果公司对GCD的封装,完全面向对象,但是比GCD拥有更强的可控性和代码可读性。所以使用起来更好理解。 NSOperation是一个抽象类,它不能直接使用,所以你必须使用NSOperation子类,使用最多的是它的两个子类:NSInvocationOperation和NSBlockOperation,但你也可以继承NSOperation来创建自己的类来执行操作。

1、NSBlockOperation:使用这个类来用一个或多个block初始化操作,操作本身可以包含多个块。当所有block被执行操作将被视为完成。

2、NSInvocationOperation:使用这个类来初始化一个操作,它包括指定对象的调用selector。

另外还有一些其他的方法:

取消操作:

[operation cancel];
复制代码

返回当前操作相对于调用start方法的线程是同步还是异步执行,默认返回是NO,表示操作与调用线程同步执行。

[operation isConcurrent];
复制代码

二、NSInvocationOperation

使用这个类来初始化一个操作,它包括指定对象的调用selector。

注意:

使用NSInvocationOperation开启一个任务默认是在主线程中执行,只有添加到队列中才会开启新的线程。即如果操作没有放到队列中queue中,都是同步执行。只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作。

三、NSBlockOperation

使用这个类来用一个或多个block初始化操作,操作本身可以包含多个块。当所有block被执行操作将被视为完成。

从运行的结果可以看出,NSBlockOperation确实实现了多线程。但是我们可以看到,它并非是将所有的block都放到放到了子线程中。通过上面的打印记录我们可以发现,它会优先将block放到主线程中执行,若主线程已有待执行的代码,就开辟新的线程,但最大并发数为4(包括主线程在内)。如果block数量大于了4,那么剩下的Block就会等待某个线程空闲下来之后被分配到该线程,且依然是优先分配到主线程。

四、自定义NSOperation

如果NSInvocationOperation和NSBlockOperation对象不能满足需求,可以自定义NSOperation,添加我们想要的功能。目前,我们可以自定义非并发和并发两种不同类型的NSOperation子类,而自定义一个前者要比后者简单得多。

1、非并发的operation 对于一个非并发的operation,我们需要做的就只是执行main方法中的任务以及能够正常响应取消事件就可以了,其它的复杂工作比如依赖配置、KVO 通知等NSOperation类都已经帮我们处理好了。

2、正确响应取消事件

当一个operation开始执行后,它会一直执行它的任务直到完成或被取消为止。可以在任意时间点取消一个operation,甚至在operation执行之前。尽管NSOperation提供了一个方法,让应用取消一个操作,但是识别出取消事件则是我们自己的事情。如果operation直接终止, 可能无法回收所有已分配的内存或资源。为了让自定义的operation能够支持取消事件,NSOperation对象需要定期地调用isCancelled方法检测操作是否已经被取消,如果返回YES(表示已取消),则立即退出执行。根据苹果官方的说法,isCancelled方法本身是足够轻量的,所以就算是频繁地调用它也不会给系统带来太大的负担。

以下地方可能需要调用isCancelled:

  • 在开始执行任务之前。
  • 在循环的每次迭代过程中,如果每个迭代相对较长可能需要调用多次。
  • 代码中相对比较容易中止操作的任何地方。

注意:

并发的operation,我会在有时间单独拿出来。

五、NSOPerationQueue

NSOperationQueue就是执行NSOperation的队列,我们可以将一个或多个NSOperation对象放到队列中去执行,而且是异步执行的。一个NSOperation对象可以通过调用start方法来执行任务,但是默认是同步执行的。

从运行结果可以看出,NSInvocationOperation和NSBlockOperation是异步执行的,NSBlockOperation中的每一个Block也是异步执行且都在子线程中执行,并且这些任务是并行执行的。

六、添加NSOperation的依赖对象

当某个NSOperation对象依赖于其它NSOperation对象的完成时,就可以通过addDependency方法添加一个或者多个依赖的对象,只有所有依赖的对象都已经完成操作,当前NSOperation对象才会开始执行操作。需要先添加依赖关系,再将操作添加到队列中。另外,通过removeDependency方法来删除依赖对象。

从运行结果中可以看出,默认是按照添加顺序执行的,先执行operation1,再执行operation2

场景:设置线程1依赖线程2,线程2依赖线程3,线程3依赖线程4。

从运行结果中看出,线程1依赖线程2,线程2依赖线程3,线程3依赖线程4。

注意:

使用依赖关系需要注意,依赖关系不局限于相同queue中的NSOperation对象,NSOperation对象会管理自己的依赖, 因此完全可以在不同的queue之间的NSOperation对象创建依赖关系。不能创建环形依赖,比如A依赖B,B依赖A,这是错误的。

七、设置queue的最大并发操作数量

由于并发的线程越多越耗资源,在queue队列中可以设置同时并发线程的数量,来进行控制,通过调用setMaxConcurrentOperationCount方法可以设置queue的最大并发操作数量。

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.maxConcurrentOperationCount = 10;
复制代码

设置queue的最大并发操作数量需要注意

1、最大并发数是有上限的,即使你设置为100,它也不会超过其上限,而这个上限的数目也是由具体运行环境决定的。

2、设置最大并发数一定要在NSOperationQueue初始化后设置。

八、取消Operations

线程调用start方法后并不是立即执行,而是进入一个就绪的状态,由系统调度执行。一旦添加到operation queue,queue就拥有了这个Operation对象并且不能被删除,唯一能做的事情是取消。你可以调用Operation对象的cancel方法取消单个操作。

for (NSOperation *operation in self.queue.operations) {
    // 取消一个NSOperation
    [operation cancel];
}

复制代码

也可以调用operation queue的cancelAllOperations方法取消当前queue中的所有操作。

// 取消queue中所有的操作  
[queue cancelAllOperations];  
复制代码

九、暂停和继续queue

如果你想临时暂停Operations的执行,可以使用queue的setSuspended:方法暂停queue。不过暂停一个queue不会导致正在执行的operation在任务中途暂停,只是简单地阻止调度新Operation执行。你可以在响应用户请求时,暂停一个queue来暂停等待中的任务。稍后根据用户的请求,可以再次调用setSuspended:方法继续queue中operation的执行。

// 暂停queue  
[queue setSuspended:YES];  

// 继续queue  
[queue setSuspended:NO];  
复制代码
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值