(五十六)iOS多线程之NSOperation
NSOpertation是一套OC的API,是对GCD进行的Cocoa抽象。
NSOperation有两种不同类型的队列,主队列和自定义队列。
主队列运行于主线程上,自定义队列在后台运行。
【NSBlockOperation】
通过Block创建任务,下面比较主队列和自定义队列的区别:
将自定义队列声明为成员变量,并进行初始化:
@property (nonatomic, strong) NSOperationQueue *myqueue;
self.myqueue = [[NSOperationQueue alloc] init];
获取主队列的方法为[NSOperationQueue mainQueue]。
队列有一个方法addOperationWithBlock方法用于添加一个用Block描述的任务。
具体代码为:
- (void)NSBlockOperation{
// 自定义队列在子线程中运行。
[self.myqueue addOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]);
}];
// 主队列任务在主线程中运行。
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"%@",[NSThread currentThread]);
}];
}
执行这个方法,得到的结果如下,可见与上面的描述相符。
2015-02-17 10:46:15.308 NSOpertaion[709:17138] <NSThread: 0x7b9aa440>{number = 2, name = (null)}
2015-02-17 10:46:15.319 NSOpertaion[709:17067] <NSThread: 0x7b978550>{number = 1, name = main}
【NSInvocationOperation】
需要定义一个回调方法,好处是可以接收一个id类型的object作为消息。
例如:
- (void)NSInvocationOperation{
NSDictionary *msg = @{@"name" : @"op",@"message" : @"hello"};
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(InvocationCall:) object:msg];
[self.myqueue addOperation:op];
}
实现回调方法:
- (void)InvocationCall:(id)obj{
NSLog(@"%@ with object %@",[NSThread currentThread],obj);
}
调用后,打印的结果如下,可以看到object对象被传了过来。
2015-02-17 10:56:03.764 NSOpertaion[812:26537] <NSThread: 0x7ba6eb10>{number = 2, name = (null)} with object {
message = hello;
name = op;
}
【任务执行顺序】
在默认情况下,自定义队列是并行队列,执行无序;而主队列为串行队列,有序执行。下面进行实验验证说法:
// 自定义队列在子线程中运行。
for (int i = 0; i < 9; i++) {
[self.myqueue addOperationWithBlock:^{
NSLog(@"%@ with no %d",[NSThread currentThread],i);
}];
} // 主队列任务在主线程中运行。
for (int i = 0; i < 9; i++) {
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
NSLog(@"%@ with no %d",[NSThread currentThread],i);
}];
}
执行结果如下,可见与上面的描述相同。
2015-02-17 11:04:08.421 NSOpertaion[919:32337] <NSThread: 0x7bf91f50>{number = 9, name = (null)} with no 6
2015-02-17 11:04:08.421 NSOpertaion[919:32331] <NSThread: 0x7bf91c10>{number = 4, name = (null)} with no 1
2015-02-17 11:04:08.421 NSOpertaion[919:32338] <NSThread: 0x7bf915c0>{number = 6, name = (null)} with no 5
2015-02-17 11:04:08.421 NSOpertaion[919:32336] <NSThread: 0x7dab62c0>{number = 7, name = (null)} with no 4
2015-02-17 11:04:08.421 NSOpertaion[919:32339] <NSThread: 0x7dab61b0>{number = 3, name = (null)} with no 7
2015-02-17 11:04:08.421 NSOpertaion[919:32330] <NSThread: 0x7dab6110>{number = 2, name = (null)} with no 0
2015-02-17 11:04:08.421 NSOpertaion[919:32341] <NSThread: 0x7d97b3f0>{number = 5, name = (null)} with no 8
2015-02-17 11:04:08.421 NSOpertaion[919:32328] <NSThread: 0x7be6d450>{number = 10, name = (null)} with no 3
2015-02-17 11:04:08.421 NSOpertaion[919:32329] <NSThread: 0x7dab6450>{number = 8, name = (null)} with no 2
2015-02-17 11:04:08.448 NSOpertaion[919:32281] <NSThread: 0x7d96f040>{number = 1, name = main} with no 0
2015-02-17 11:04:08.449 NSOpertaion[919:32281] <NSThread: 0x7d96f040>{number = 1, name = main} with no 1
2015-02-17 11:04:08.449 NSOpertaion[919:32281] <NSThread: 0x7d96f040>{number = 1, name = main} with no 2
2015-02-17 11:04:08.449 NSOpertaion[919:32281] <NSThread: 0x7d96f040>{number = 1, name = main} with no 3
2015-02-17 11:04:08.450 NSOpertaion[919:32281] <NSThread: 0x7d96f040>{number = 1, name = main} with no 4
2015-02-17 11:04:08.450 NSOpertaion[919:32281] <NSThread: 0x7d96f040>{number = 1, name = main} with no 5
2015-02-17 11:04:08.450 NSOpertaion[919:32281] <NSThread: 0x7d96f040>{number = 1, name = main} with no 6
2015-02-17 11:04:08.450 NSOpertaion[919:32281] <NSThread: 0x7d96f040>{number = 1, name = main} with no 7
2015-02-17 11:04:08.450 NSOpertaion[919:32281] <NSThread: 0x7d96f040>{number = 1, name = main} with no 8
【自定义队列顺序执行】
使用NSBlockOperation对象的addDependency设置依赖关系,只有依赖的对象执行完毕后,自己才能执行。
例如下面的例子,三个任务要顺序执行,先下载,再处理,最后显示,通过这样的设定可以保证顺序:
- (void)SerialOperation{
NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"下载");
}];
NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"处理");
}];
NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"显示");
}];
[op2 addDependency:op1];
[op3 addDependency:op2];
[self.myqueue addOperation:op1];
[self.myqueue addOperation:op2];
[self.myqueue addOperation:op3];
}
注意这个执行和串行队列的异步任务不同点是,串行队列的异步任务仅仅开一个线程;自定义队列的顺序执行可能开辟多个但不会太多个线程。
注意上面的代码有一定的问题,因为显示只有主线程可以处理,所以op3应该放入主线程。
Tip:依赖关系可以跨队列,因此op3依赖op2在主线程中仍然有效,只需要修改op3的入队代码为:
[[NSOperationQueue mainQueue] addOperation:op3];
Tip:注意避开循环依赖,程序会崩溃。
【设定多线程的最大开销】
设定同时执行的最大线程数:通过队列的setMaxConcurrentOperationCount方法来设定,例如:
[self.myqueue setMaxConcurrentOperationCount:3];
应用场景:网络通信,例如3G开3个子线程,WIFI开6个子线程。
Tip:线程的开销主要是CPU和内存,还会耗电,因此应该考虑软件的能耗。
Tip:AFNetworing的底层是使用GCD开发的,接口是NSOperation。
(五十六)iOS多线程之NSOperation的更多相关文章
- iOS 多线程之NSOperation篇举例详解
这篇博客是接着总篇iOS GCD NSOperation NSThread等多线程各种举例详解写的一个支篇.总篇也包含了此文的链接.本文讲解的知识点有NSBlockOperationClick,队列, ...
- iOS多线程之NSOperation详解
使用NSOperation和NSOperationQueue进行多线程开发,只要将一个NSOperation(实际开发中需要使用其子类 NSInvocationOperation,NSBlockOpe ...
- IOS多线程之NSOperation学习总结
NSOperation简介 1.NSOperation的作用 配合使用NSOperation和NSOperationQueue也能实现多线程编程 2.NSOperation和NSOperationQu ...
- iOS多线程之NSOperation,NSOperationQueue
使用 NSOperation的方式有两种, 一种是用定义好的两个子类: NSInvocationOperation 和 NSBlockOperation. 另一种是继承NSOperation 如果你也 ...
- iOS多线程之NSOperation和NSOperationQueue的使用
一:NSOperation 两个子类+重写main方法 NSInvocationOperation NSBlockOperation 有个类方法 BlockOprationWith: 还有就是自己个子 ...
- ios多线程之NSOperation
使用 NSOperation的方式有两种, 一种是用定义好的两个子类: NSInvocationOperation 和 NSBlockOperation. 另一种是继承NSOperation 如果你也 ...
- iOS多线程之8.NSOPeration的其他用法
本文主要对NSOPeration的一些重点属性和方法做出介绍,以便大家可以更好的使用NSOPeration. 1.添加依赖 - (void)addDependency:(NSOperation * ...
- iOS多线程之GCD小记
iOS多线程之GCD小记 iOS多线程方案简介 从各种资料中了解到,iOS中目前有4套多线程的方案,分别是下列4中: 1.Pthreads 这是一套可以在很多操作系统上通用的多线程API,是基于C语言 ...
- 【Visual C++】游戏开发五十六 浅墨DirectX教程二十三 打造游戏GUI界面(一)
本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/16384009 作者:毛星云 ...
随机推荐
- 当我们在谈论JMM(Java memory model)的时候,我们在谈论些什么
前面几篇中,我们谈论了synchronized.final以及voilate的用法和底层实现,都绕不开一个话题-Java内存模型(java memory model,简称JMM).Java内存模型是保 ...
- 聊聊jstack的工作原理
实现一个jstack 在聊Jstack得工作原理前呢,不如让我们先写一个简单的jstack玩玩.不用怕,很简单的,就几行代码的事,看: public class MyJstack { public s ...
- Docker 备份、恢复、迁移数据卷
可以利用数据卷对其中的数据进行进行备份.恢复和迁移. 备份 首先使用 --volumes-from 标记来创建一个加载 dbdata 容器卷的容器,并从本地主机挂载当前到容器的 /backup 目录. ...
- iOS控制反转(IoC)与依赖注入(DI)的实现
背景 最近接触了一段时间的SpringMVC,对其控制反转(IoC)和依赖注入(DI)印象深刻,此后便一直在思考如何使用OC语言较好的实现这两个功能.Java语言自带的注解特性为IoC和DI带来了极大 ...
- Minor GC、Major GC和Full GC之间的区别
在 Plumbr 从事 GC 暂停检测相关功能的工作时,我被迫用自己的方式,通过大量文章.书籍和演讲来介绍我所做的工作.在整个过程中,经常对 Minor.Major.和 Full GC 事件的使用感到 ...
- mongo 读分析
分布式读 读冲突 分布式中数据库有多份数据,各份数据可能存在不一致性. mongo 只会写到primary节点上,理论上来说不会有文档冲突,也就是说数据库中的数据都以primary节点为标准. 但是有 ...
- Xcode 调试技巧 --常用命令和断点
Xcode 中的调试技巧与我们的日常开发息息相关,而这些调试技巧在我们解决Bug时,常常有事半功倍的作用,经常会用到的有各种断点 和 命令.而这些调试技巧也经常会在面试中问到,所以不知道的就来看看吧. ...
- Swift3的playground中对UI直接测试支持的改变
我们知道在Xcode的playground中不仅可以测试console代码,还可以测试UI代码,甚至我们可以测试SpriteKit中的场景,有兴趣的童鞋可以看我之前写的这一篇blog: Xcode的p ...
- 微信小程序基础之交互操作控件
好久没有写关于微信小程序的文章了,今天简单的发表一篇,内容比较简单,包括:ActionSheet上拉菜单.AlertAction提示框.SuccessAction完成框.LoadingAction加载 ...
- Android图表库MPAndroidChart(八)——饼状图的扩展:折线饼状图
Android图表库MPAndroidChart(八)--饼状图的扩展:折线饼状图 我们接着上文,饼状图的扩展,增加折现的说明,来看下我们要实现的效果 因为之前对MPAndroidChart的熟悉,所 ...