原文链接:http://www.jianshu.com/p/2de9c776f226

NSOperation是OC中多线程技术的一种,是对GCD的OC包装.它包含队列(NSOperationQueue)和操作(NSOperation)两个基本要素.

通过这篇文章你可以了解到:

  • 怎样使用NSOperation
  • 怎样使用NSOperationQueue
  • 如何给NSOperationQueue设置并发数
  • NSOperationQueue的暂停恢复和取消
  • 通过添加依赖影响操作的执行顺序
  • NSOperation的进程间通信

怎样使用NSOperation

  • NSOperation本身是一个抽象类,要使用可以通过以下几个办法:

    • 使用NSInvocationOperation
    • 使用NSBlockOperation
    • 自定义NSOperation的子类

使用

  • NSInvocationOperation
NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(task) object:nil];
// 调用start方法执行操作op操作
[op start];
  • NSBlockOperation
NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"task0---%@", [NSThread currentThread]);
}];
[op start];

根据打印的结果我们会发现,直接调用start方法时,系统并不会开辟一个新的线程去执行任务,任务会在当前线程同步执行.

注意: 这里我们说的是当前线程而非主线程,意即:如果是在主线程中调用op的start方法,那么该任务是在主线程中执行;但如果是在其他子线程调用start方法,任务则是在其他子线程执行.

当然NSBlockOperation还有一种使用方法addExecutionBlock:使得我们可以给其添加更多的操作,使用如下:

NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"task0---%@", [NSThread currentThread]);
}]; [op addExecutionBlock:^{
NSLog(@"task1----%@", [NSThread currentThread]);
}]; [op addExecutionBlock:^{
NSLog(@"task2----%@", [NSThread currentThread]);
}]; // 开始必须在添加其他操作之后
[op start];

由打印的结果发现: task0的结果和前面的结论一样,是执行在主线程中的(因为是在主线程中调用start方法),但task1和task2都是在自己的新线程中执行.也就是说:当NSBlockOperation封装的操作数大于1的时候,就会执行异步操作.

  • 自定义NSOperation

自定义NSOperation的方法也很简单,我们需要做到下面几个步骤:
1.子类化NSOperation
2.在.m文件里面实现-(void)main方法
3.初始化该操作的时候直接调用alloc及init即可
4.同样可以通过start方法让你自定义的任务跑在当前线程中
关键代码:

自定义NSOperation的实现文件:

#import "AROperation.h"
@implementation AROperation
- (void)main {
NSLog(@"this is my custom operation ---- %@", [NSThread currentThread]);
}
@end

使用(在任何需要启用该任务的地方):

// 该操作被执行时就会执行op内部定义的任务
AROperation *op = [[AROperation alloc] init];
[op start];

怎样使用NSOperationQueue

NSOperation的start方法默认是同步执行任务,这样的使用并不多见,只有将NSOperation与NSOperationQueue进行结合,才会发挥出这种多线程技术的最大功效.当NSOperation被添加到NSOperationQueue中后,就会全自动地执行异步操作.

  • NSOperationQueue的种类:

    • 自带主队列[NSOperationQueue mainQueue]: 添加到主队列中的任务都会在主线程中执行
    • 自己创建队列(非主队列)
      NSOperationQueue *queue = [[NSOperationQueue alloc] init];: 这种队列同时包含串行、并发的功能,添加到非主队列的任务会自动放到子线程中执行
  • 向NSOperationQueue中添加操作:

    • 直接添加
      [queue addOperation:op1];
    • 使用block添加,block的内容会被包装成operation对象添加到队列
      [queue addOperationWithBlock:^{
      }];

      操作一但被到添加到队列中,就会自动异步执行.

设置NSOperationQueue的最大并发数

NSOperationQueue可以通过以下方法设置最大并发数,
setMaxConcurrentOperationCount:,值得注意的是:当并发数为1就变成了串行执行任务

NSOperationQueue的暂停恢复和取消

  • 取消

    • NSOperation有一个cancel方法可以取消单个操作
    • NSOperationQueue的cancelAllOperations相当于队列中的每个operation调用了cancel方法,会取消队列里面全部的操作.
    • 但是,不能取消正在进行中的任务,队列调用了cancelAllOperations后会等当前正在进行的任务执行完闭后取消后面的操作
  • 挂起和恢复
    • isSuspended : 判断是否挂起
    • setSuspended: YES表示挂起,NO表示恢复
    • 和取消功能类似,我们同样不能挂起正在运行中的操作,队列会等当前操作结束后将后面的操作暂停(挂起)

因此, 我们在自定义NSOperation的时候需要注意,最好可以经常通过判断isCancelled方法检测操作是否被取消,以响应外部可能进行的取消操作.如:

// 自定义NSOperation类.m文件的main方法实现
- (void)main {
for (NSInteger i = 0; i < 1000; i++) {
NSLog(@"SubTask---0---%zd",i);
}
// 判断当前任务是否被取消,如果已经取消,及时返回
if (self.cancelled) {
return;
} for (NSInteger i = 0; i < 1000; i++) { NSLog(@"SubTask---1---%zd", i);
}
if (self.cancelled) {
return;
} for (NSInteger i = 0; i < 1000; i++) {
NSLog(@"SubTask---2---%zd",i);
}
}

添加依赖和监听

  • 通过设置操作间的依赖,可以确定这些操作的执行顺序
    如:
[op3 addDependency:op1];
[op3 addDependency:op2]; 表示op3会在op1和op2都执行完毕后才执行

添加依赖的时候要注意防止添加循环依赖,此外我们还可以在不同队列的operation之间添加依赖

  • 监听

    • op.completeBlock可以监听一个操作执行完毕的时刻,这个block里面可以添加一些我们需要执行的操作
    • 这个block里面的操作仍然是在子线程执行,但不一定和被监听的操作在同一个线程

线程间通信

有时我们在子线程中执行完一些操作的时候,需要回到主线程做一些事情(如进行UI操作),因此需要从当前线程回到主线程,以下载并显示图片为例,方法如下:

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
// 子线程下载图片
[queue addOperationWithBlock:^{
NSURL *url = [NSURL URLWithString:@"http://img.pconline.com.cn/images/photoblog/9/9/8/1/9981681/200910/11/1255259355826.jpg"];
NSData *data = [NSData dataWithContentsOfURL:url];
UIImage *image = [[UIImage alloc] initWithData:data];
// 回到主线程进行显示
[[NSOperationQueue mainQueue] addOperationWithBlock:^{
self.imageView.image = image;
}];
}];

NSOperation的使用还是比较简单的,但是要注意的细节比较多,一些方法比较容易被忽略,于是乎特此总结一下.这里就不上传示例代码了,有问题的童鞋可以直接留言.

认识和使用NSOperation的更多相关文章

  1. iOS多线程之9.自定义NSOperation

      本文主要讲如何自定义NSOperation,以及自定义NSOperation的一些注意事项,以下载图片为例. 新建一个类,继承于NSOperation. CustomOperation.h 代码 ...

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

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

  3. iOS多线程之7.NSOperation的初识

    NSOperation和GCD一样,不用我们管理线程的生命周期,加锁等问题,只要把操作封装进NSOperation中,系统会自动帮我们创建线程,执行操作.而且他是面向对象的,我们看起来更容易理解,使用 ...

  4. 4.4 多线程进阶篇<下>(NSOperation)

    本文并非最终版本,如有更新或更正会第一时间置顶,联系方式详见文末 如果觉得本文内容过长,请前往本人"简书" 本文源码 Demo 详见 Github https://github.c ...

  5. 多线程下NSOperation、NSBlockOperation、NSInvocationOperation、NSOperationQueue的使用

    本篇文章主要介绍下多线程下NSOperation.NSBlockOperation.NSInvocationOperation.NSOperationQueue的使用,列举几个简单的例子. 默认情况下 ...

  6. iOS NSOperation 封装 通知实现界面更新

    #import <Foundation/Foundation.h> #import <UIKit/UIKit.h> @interface MYOperation : NSOpe ...

  7. iOS NSOperation 异步加载图片 封装NSOperation 代理更新

    #import <Foundation/Foundation.h> @class MYOperation; @protocol MYOperationDelecate <NSObje ...

  8. 3.多线程NSOperation

    1.NSOperation的基本操作 使用NSOperation的两个子类,NSInvocationOperation 和 NSBlockOperation 创建操作,然后将操作添加到队列中去执行 / ...

  9. NSOperation的start与main,并发与非并发。

    http://blog.csdn.net/a2331046/article/details/52294006 在ios4以前,只有非并发的情况下,队列会为operation开启一个线程来执行.如果是并 ...

随机推荐

  1. [Java编程思想-学习笔记]第1章 对象导论

    1.1  抽象过程 Java是一门面向对象的语言,它的一个优点在于只针对待解问题抽象,而不用为具体的计算机结构而烦心,这使得Java有完美的移植性,也即Java的口号"Write Once, ...

  2. SQL Server Integration Services(SSIS) 包配置与部署

    SSIS配置此处的配置方式,主要针对到正式服务器上要修改服务器名,和连接服务器等配置注意:1. 包配置在windows2008上生成后,在windows2003上mysql的配置无法使用,总是报错连接 ...

  3. ARM汇编程序结构

    ARM汇编程序结构 一个ARM程序可以被划分为多个代码段和数据段,在汇编的时候这些段会被形成一个可执行文件 .text ;正文段,包含程序的指令代码 .data ;数据段,包含固定的数据,如常量,字符 ...

  4. ELF Format 笔记(十四)—— 段内容

    ilocker:关注 Android 安全(新手) QQ: 2597294287 一个段 (segment) 由一个或多个节 (section) 组成,但这对 android linker 是透明的, ...

  5. gdb脚本

    一.简介 作为UNIX/Linux下使用广泛的调试器,gdb不仅提供了丰富的命令,还引入了对脚本的支持:一种是对已存在的脚本语言支持,比如python,用户可以直接书写python脚本,由gdb调用p ...

  6. 一种可实时处理 O(1)复杂度图像去雾算法的实现。

    在我博文的一系列的文章,有不少算法都于去雾有关,比如限制对比度自适应直方图均衡化算法原理.实现及效果.局部自适应自动色阶/对比度算法在图像增强上的应用这两个增强算法都有一定的去雾能力,而最直接的就是& ...

  7. C#学习笔记-图像处理篇(一)绘制公章

    上个月免费帮别人做事,就一直在服务员和程序员中来回切换,所以好多事情都弄得乱糟糟的,家里也是乱七八糟的,所以学习这一块也放了一段时间. 刚刚开始当服务员的时间看到了形形色色的人,觉得很好玩,他们每个人 ...

  8. 【Python网络编程】利用Python进行TCP、UDP套接字编程

    之前实现了Java版本的TCP和UDP套接字编程的例子,于是决定结合Python的学习做一个Python版本的套接字编程实验. 流程如下: 1.一台客户机从其标准输入(键盘)读入一行字符,并通过其套接 ...

  9. Oracle基本数据类型

    一 字符串类型 字符串数据类型还可以依据存储空间分为固定长度类型(CHAR/NCHAR) 和可变长度类型(VARCHAR2/NVARCHAR2)两种. 所谓固定长度:是指虽然输入的字段值小于该字段的限 ...

  10. CH Round #72树洞[二分答案 DFS&&BFS]

    树洞 CH Round #72 - NOIP夏季划水赛 描述 在一片栖息地上有N棵树,每棵树下住着一只兔子,有M条路径连接这些树.更特殊地是,只有一棵树有3条或更多的路径与它相连,其它的树只有1条或2 ...