一、简介

一个NSOperation对象可以通过调用start方法来执行任务,默认是同步执行的。也可以将NSOperation添加到一个NSOperationQueue(操作队列)中去执行,而且是异步执行的。

创建一个操作队列:

NSOperationQueue *queue = [[NSOperationQueue alloc] init];  

二、添加NSOperation到NSOperationQueue中

1.添加一个operation

[queue addOperation:operation];  

2.添加一组operation

[queue addOperations:operations waitUntilFinished:NO];  

3.添加一个block形式的operation

[queue addOperationWithBlock:^() {
NSLog(@"执行一个新的操作,线程:%@", [NSThread currentThread]);
}];

NSOperation添加到queue之后,通常短时间内就会得到运行。但是如果存在依赖,或者整个queue被暂停等原因,也可能需要等待。

注意:NSOperation添加到queue之后,绝对不要再修改NSOperation对象的状态。因为NSOperation对象可能会在任何时候运行,因此改变NSOperation对象的依赖或数据会产生不利的影响。你只能查看NSOperation对象的状态, 比如是否正在运行、等待运行、已经完成等

三、添加NSOperation的依赖对象
1.当某个NSOperation对象依赖于其它NSOperation对象的完成时,就可以通过addDependency方法添加一个或者多个依赖的对象,只有所有依赖的对象都已经完成操作,当前NSOperation对象才会开始执行操作。另外,通过removeDependency方法来删除依赖对象。

[operation2 addDependency:operation1];  

依赖关系不局限于相同queue中的NSOperation对象,NSOperation对象会管理自己的依赖, 因此完全可以在不同的queue之间的NSOperation对象创建依赖关系

唯一的限制是不能创建环形依赖,比如A依赖B,B依赖A,这是错误的

2.依赖关系会影响到NSOperation对象在queue中的执行顺序,看下面的例子:

1> 没有设置依赖关系

NSOperationQueue *queue = [[NSOperationQueue alloc] init];  

NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第1次操作,线程:%@", [NSThread currentThread]);
}]; NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第2次操作,线程:%@", [NSThread currentThread]);
}]; [queue addOperation:operation1];
[queue addOperation:operation2];

打印信息

-- ::35.024 thread[:3d13] 执行第1次操作,线程:<NSThread: 0x7658570>{name = (null), num = }
-- ::35.063 thread[:] 执行第2次操作,线程:<NSThread: 0x765a2e0>{name = (null), num = }

可以看出,默认是按照添加顺序执行的,先执行operation1,再执行operation2
 2> 设置了依赖关系

NSOperationQueue *queue = [[NSOperationQueue alloc] init];  

NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第1次操作,线程:%@", [NSThread currentThread]);
}]; NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^(){
NSLog(@"执行第2次操作,线程:%@", [NSThread currentThread]);
}];
// operation1依赖于operation2
[operation1 addDependency:operation2]; [queue addOperation:operation1];
[queue addOperation:operation2];

打印信息:

-- ::16.260 thread[:1b03] 执行第2次操作,线程:<NSThread: 0x7634490>{name = (null), num = }
-- ::16.285 thread[:] 执行第1次操作,线程:<NSThread: 0x9138b50>{name = (null), num = }

可以看出,先执行operation2,再执行operation1

四、修改Operations的执行顺序

对于添加到queue中的operations,它们的执行顺序取决于2点:

1.首先看看NSOperation是否已经准备好:是否准备好由对象的依赖关系确定

2.然后再根据所有NSOperation的相对优先级来确定。优先级等级则是operation对象本身的一个属性。默认所有operation都拥有“普通”优先级,不过可以通过setQueuePriority:方法来提升或降低operation对象的优先级。优先级只能应用于相同queue中的operations。如果应用有多个operation queue,每个queue的优先级等级是互相独立的。因此不同queue中的低优先级操作仍然可能比高优先级操作更早执行。

注意:优先级不能替代依赖关系,优先级只是对已经准备好的 operations确定执行顺序。先满足依赖关系,然后再根据优先级从所有准备好的操作中选择优先级最高的那个执行。

五、设置队列的最大并发操作数量

队列的最大并发操作数量,意思是队列中最多同时运行几条线程

虽然NSOperationQueue类设计用于并发执行Operations,你也可以强制单个queue一次只能执行一个Operation。setMaxConcurrentOperationCount:方法可以配置queue的最大并发操作数量。设为1就表示queue每次只能执行一个操作。不过operation执行的顺序仍然依赖于其它因素,比如operation是否准备好和operation的优先级等。因此串行化的operation queue并不等同于GCD中的串行dispatch queue

// 每次只能执行一个操作
queue.maxConcurrentOperationCount = ;
// 或者这样写
[queue setMaxConcurrentOperationCount:];

六、取消Operations

一旦添加到operation queue,queue就拥有了这个Operation对象并且不能被删除,唯一能做的事情是取消。你可以调用Operation对象的cancel方法取消单个操作,也可以调用operation queue的cancelAllOperations方法取消当前queue中的所有操作。

// 取消单个操作
[operation cancel]; // 取消queue中所有的操作
[queue cancelAllOperations];

七、等待Options完成

为了最佳的性能,你应该设计你的应用尽可能地异步操作,让应用在Operation正在执行时可以去处理其它事情。如果需要在当前线程中处理operation完成后的结果,可以使用NSOperation的waitUntilFinished方法阻塞当前线程,等待operation完成。通常我们应该避免编写这样的代码,阻塞当前线程可能是一种简便的解决方案,但是它引入了更多的串行代码,限制了整个应用的并发性,同时也降低了用户体验。绝对不要在应用主线程中等待一个Operation,只能在第二或次要线程中等待。阻塞主线程将导致应用无法响应用户事件,应用也将表现为无响应。

// 会阻塞当前线程,等到某个operation执行完毕
[operation waitUntilFinished];

除了等待单个Operation完成,你也可以同时等待一个queue中的所有操作,使用NSOperationQueue的waitUntilAllOperationsAreFinished方法。注意:在等待一个 queue时,应用的其它线程仍然可以往queue中添加Operation,因此可能会加长线程的等待时间。

// 阻塞当前线程,等待queue的所有操作执行完毕
[queue waitUntilAllOperationsAreFinished];

八、暂停和继续queue

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

// 暂停queue
[queue setSuspended:YES]; // 继续queue
[queue setSuspended:NO];

IOS开发 多线程编程 - NSOperationQueue的更多相关文章

  1. IOS开发 多线程编程 - NSThread

    每个iOS应用程序都有个专门用来更新显示UI界面.处理用户的触摸事件的主线程,因此不能将其他太耗时的操作放在主线程中执行,不然会造成主线程堵塞(出现卡机现象),带来极坏的用户体验.一般的解决方案就是将 ...

  2. iOS开发多线程编程2 - NSOperation

    1.简介 NSOperation实例封装了需要执行的操作和执行操作所需的数据,并且能够以并发或非并发的方式执行这个操作. NSOperation本身是抽象基类,因此必须使用它的子类,使用NSOpera ...

  3. IOS开发 多线程编程 - NSOperation

    一.NSOperation 1.简介 NSOperation实例封装了需要执行的操作和执行操作所需的数据,并且能够以并发或非并发的方式执行这个操作. NSOperation本身是抽象基类,因此必须使用 ...

  4. iOS开发多线程篇—NSOperation简单介绍

    iOS开发多线程篇—NSOperation简单介绍 一.NSOperation简介 1.简单说明 NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现 ...

  5. iOS开发——多线程OC篇&多线程详解

    多线程详解 前面介绍了多线程的各种方式及其使用,这里补一点关于多线程的概念及相关技巧与使用,相信前面不懂的地方看了这里之后你就对多线程基本上没有什么问题了! 1——首先ios开发多线程中必须了解的概念 ...

  6. iOS开发多线程篇 09 —NSOperation简单介绍

    iOS开发多线程篇—NSOperation简单介绍 一.NSOperation简介 1.简单说明 NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现 ...

  7. iOS开发多线程篇—NSOperation基本操作

    iOS开发多线程篇—NSOperation基本操作 一.并发数 (1)并发数:同时执⾏行的任务数.比如,同时开3个线程执行3个任务,并发数就是3 (2)最大并发数:同一时间最多只能执行的任务的个数. ...

  8. iOS开发多线程篇—自定义NSOperation

    iOS开发多线程篇—自定义NSOperation 一.实现一个简单的tableView显示效果 实现效果展示: 代码示例(使用以前在主控制器中进行业务处理的方式) 1.新建一个项目,让控制器继承自UI ...

  9. iOS开发多线程篇 11 —自定义NSOperation

    iOS开发多线程篇—自定义NSOperation 一.实现一个简单的tableView显示效果 实现效果展示: 代码示例(使用以前在主控制器中进行业务处理的方式) 1.新建一个项目,让控制器继承自UI ...

随机推荐

  1. IDEA 逆向工程

    今天要写一个导入功能,需要把数据库的一个表映射成一个pojo,但是这表字段不是一般的多啊...想了想能不能自动生成???在IDEA中点了半天发现还是可以的 下面介绍一下步骤: 第一步:找到这个图标,建 ...

  2. Mac与Widow下编译与运行java文件引入多个外部jar包

    记录下,以后万一用得着呢 1.MAC环境下: 前提:在终端跳转到当前的源文件目录(cd xx), 并且配置好jdk,这里面不是重点 编译命令:注意连接用  :  号 javac -cp commons ...

  3. ADO.NET 使用DELETE语句批量删除操作,提示超时,删除失败,几种优化解决思路

    起因是如此简单的一句sql 提示:Timeout 时间已到.在操作完成之前超时时间已过或服务器未响应. 提供几种解决思路: 1.检查WHERE条件中字段是否已建索引 2.检查是否被其他表引用,引用表外 ...

  4. 机器学习笔记—EM 算法

    EM 算法所面对的问题跟之前的不一样,要复杂一些. EM 算法所用的概率模型,既含有观测变量,又含有隐变量.如果概率模型的变量都是观测变量,那么给定数据,可以直接用极大似然估计法,或贝叶斯估计法来估计 ...

  5. MySQL行锁、间隙锁、Next-Key锁

    InnoDB是一个支持行锁的存储引擎,它有三种行锁的算法: Record Lock:行锁,单个行记录上的锁. Gap Lock:间隙锁,锁定一个范围,但不包括记录本身.GAP锁的目的,是为了防止幻读. ...

  6. 【Python】更优的字符串格式化方式 -- "format"替代"%s"

    背景 前段时间看了一篇介绍Python的代码技巧的文章,建议格式化字符串时使用"format"代替使用"%",但是没有说明原因.各博客网站介绍相关用法的博客很多 ...

  7. 初识 JVM

    发展历史 1996年,SUN JDK 1.0 Classic VM 发布,纯解释运行,使用外挂进行JIT 1997年 JDK1.1 发布.包含了:AWT.内部类.JDBC.RMI.反射 1998年 J ...

  8. 关于 MongoDB 复制集

    为什么要使用复制集 1.备份数据通过自带的 mongo_dump/mongo_restore 工具也可以实现备份,但是毕竟没有复制集的自动同步备份方便. 2.故障自动转移部署了复制集,当主节点挂了后, ...

  9. ubuntu 安装包过程中遇到的一个错误解决办法

    错误提示如下: 将会安装下列额外的软件包: libdigest-hmac-perl libqt5test5下列[新]软件包将被安装: libdigest-hmac-perl下列软件包将被升级: lib ...

  10. Python 排序---sort与sorted学习

    当我们从数据库中获取一写数据后,一般对于列表的排序是经常会遇到的问题,今天总结一下python对于列表list排序的常用方法: 第一种:内建方法sort() 可以直接对列表进行排序 用法: list. ...