前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >iOS多线程之四:NSOperation的使用

iOS多线程之四:NSOperation的使用

作者头像
s_在路上
发布2018-09-11 17:11:44
1.1K0
发布2018-09-11 17:11:44
举报
文章被收录于专栏:iOS 开发杂谈

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

1、NSBlockOperation:使用这个类来用一个或多个block初始化操作,操作本身可以包含多个块。当所有block被执行操作将被视为完成。 2、NSInvocationOperation:使用这个类来初始化一个操作,它包括指定对象的调用selector。

Paste_Image.png

另外还有一些其他的方法: 取消操作:

代码语言:javascript
复制
[operation cancel];

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

代码语言:javascript
复制
[operation isConcurrent];

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

Paste_Image.png

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

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

Paste_Image.png

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

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

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

Paste_Image.png

Paste_Image.png

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

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

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

Paste_Image.png

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

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

Paste_Image.png

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

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

Paste_Image.png

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

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

Paste_Image.png

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

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

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

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

设置queue的最大并发操作数量需要注意 1、最大并发数是有上限的,即使你设置为100,它也不会超过其上限,而这个上限的数目也是由具体运行环境决定的。 2、设置最大并发数一定要在NSOperationQueue初始化后设置。

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

代码语言:javascript
复制
for (NSOperation *operation in self.queue.operations) {
    // 取消一个NSOperation
    [operation cancel];
}

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

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

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

代码语言:javascript
复制
// 暂停queue  
[queue setSuspended:YES];  

// 继续queue  
[queue setSuspended:NO];  
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2016.09.07 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档