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的更多相关文章

  1. iOS 多线程之NSOperation篇举例详解

    这篇博客是接着总篇iOS GCD NSOperation NSThread等多线程各种举例详解写的一个支篇.总篇也包含了此文的链接.本文讲解的知识点有NSBlockOperationClick,队列, ...

  2. iOS多线程之NSOperation详解

    使用NSOperation和NSOperationQueue进行多线程开发,只要将一个NSOperation(实际开发中需要使用其子类 NSInvocationOperation,NSBlockOpe ...

  3. IOS多线程之NSOperation学习总结

    NSOperation简介 1.NSOperation的作用 配合使用NSOperation和NSOperationQueue也能实现多线程编程 2.NSOperation和NSOperationQu ...

  4. iOS多线程之NSOperation,NSOperationQueue

    使用 NSOperation的方式有两种, 一种是用定义好的两个子类: NSInvocationOperation 和 NSBlockOperation. 另一种是继承NSOperation 如果你也 ...

  5. iOS多线程之NSOperation和NSOperationQueue的使用

    一:NSOperation 两个子类+重写main方法 NSInvocationOperation NSBlockOperation 有个类方法 BlockOprationWith: 还有就是自己个子 ...

  6. ios多线程之NSOperation

    使用 NSOperation的方式有两种, 一种是用定义好的两个子类: NSInvocationOperation 和 NSBlockOperation. 另一种是继承NSOperation 如果你也 ...

  7. iOS多线程之8.NSOPeration的其他用法

      本文主要对NSOPeration的一些重点属性和方法做出介绍,以便大家可以更好的使用NSOPeration. 1.添加依赖 - (void)addDependency:(NSOperation * ...

  8. iOS多线程之GCD小记

    iOS多线程之GCD小记 iOS多线程方案简介 从各种资料中了解到,iOS中目前有4套多线程的方案,分别是下列4中: 1.Pthreads 这是一套可以在很多操作系统上通用的多线程API,是基于C语言 ...

  9. 【Visual C++】游戏开发五十六 浅墨DirectX教程二十三 打造游戏GUI界面(一)

    本系列文章由zhmxy555(毛星云)编写,转载请注明出处. 文章链接:http://blog.csdn.net/poem_qianmo/article/details/16384009 作者:毛星云 ...

随机推荐

  1. 转:Socket原理与编程基础

    from: http://acm.tzc.edu.cn/acmhome/projectList.do?method=projectNewsDetail&nid=2 一.Socket简介 Soc ...

  2. sa账号无法登陆sqlserver2008

    今天遇到sa无法登陆sqlserver2008的问题,原来是sa账户未启用,混合验证模式没打开,太低端了. 具体解决过程将从百度文库里查到的文章张贴如下: 出现问题 : 标题: 连接到服务器 ---- ...

  3. MongoDB 原子操作

    mongodb不支持事务,所以,在你的项目中应用时,要注意这点.无论什么设计,都不要要求mongodb保证数据的完整性. 但是mongodb提供了许多原子操作,比如文档的保存,修改,删除等,都是原子操 ...

  4. webpack4.x配置详解,多页面,多入口,多出口,新特性新坑!!

    花了差不多一天多的时间,重新撸了一遍webpack4.x的常用配置. 基本上常用的配置都熟悉了一遍,总体上来讲,为了对parcel进行反击,webpack从4.x开始,正在朝着尽可能的简化配置文件的方 ...

  5. 在Spring Boot中使用数据库事务

    我们在前面已经分别介绍了如何在Spring Boot中使用JPA(初识在Spring Boot中使用JPA)以及如何在Spring Boot中输出REST资源(在Spring Boot中输出REST资 ...

  6. android NDK的下载-文件太大

    需要FQ,建议使用VPN,下载前准备点时间配置网络环境.我的百度网盘好像有~~不过忘记地址了,改天共享,或者私聊我. 2015.4 Android 5.1 Android Studio https:/ ...

  7. 计算机网络之域名系统DNS

    域名系统DNS 域名系统DNS(Domai NameSystem)是因特网使用的命名系统,用于把便于人们使用的机器名字转换为IP地址. 许多应用层软件经常直接使用域名系统,但计算机的用户只是间接而不是 ...

  8. Swift基础之两指拉动图片变大变小

    我们在使用APP的时候,有时会发现有些图片可以通过两指进行放大.缩小,今天就实现这样的一种效果,比较简单,不喜勿喷.... var imageVi:UIImageView! = nil    var ...

  9. JVM内存区域划分(JDK6/7/8中的变化)

    前言 Java程序的运行是通过Java虚拟机来实现的.通过类加载器将class字节码文件加载进JVM,然后根据预定的规则执行.Java虚拟机在执行Java程序的过程中会把它所管理的内存划分为若干个不同 ...

  10. socket系列之客户端socket——Socket类

    假设TCP套接字服务器端已经建立好并正在监听客户端的连接了,那么客户端就可以通过Socket类来发起连接.客户端发起一个连接请求后,就被动地在等待服务器的响应.这个类同样位于java.net包中,包含 ...