原文链接: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. 谈谈yii2-GridView如何实现列表页直接修改数据

    作者:白狼 出处:http://www.manks.top/yii2_gridview_advanced.html 本文版权归作者,欢迎转载,但未经作者同意必须保留此段声明,且在文章页面明显位置给出原 ...

  2. 47个过程(PMBOK2008)

    项目管理过程 知识领域 过程组 含义 之前应完成 之后要进行 制定项目章程 整合 启动 编写一份正式批准项目并授权项目经理使用组织资源的文件的过程 无 制定项目管理计划 制定项目管理计划 整合 规划 ...

  3. IIS7如何部署asp.net网站

      第一步:发布网站 右键asp.net web项目,选择发布, 然后新建配置文件名称并选择 "文件系统" 发布方法. 目标位置选择本地新建的文件夹如: IISWebSite 第二 ...

  4. DBCC CheckDB遇到a database snapshot could not be created

    在备份一个客户的数据库时(数据库版本为SQL 2005 Express版本),做DBCC CHECKDB时遇到了下面错误信息: dbcc checkdb('DB_NAME'); 消息 5030,级别 ...

  5. MS SQL巡检系列——检查数据库上一次DBCC CHECKDB的时间

    DBCC CHECKDB检查指定数据库中的所有对象的逻辑和物理完整性,具体请参考MSDN文档.我们必须定期对数据库做完整性检查(DBCC CHECKDB),以便能及时发现一些数据库损坏(Corrupt ...

  6. SQL Server 2008 安装过程中遇到“性能计数器注册表配置单元一致性”检查失败 问题的解决方法

    操作步骤: 1. 在 Microsoft Windows 2003 或 Windows XP 桌面上,依次单击"开始"."运行",然后在"打开&quo ...

  7. DbVisualizer连接hbase

    1.添加phoneix驱动 (1).点击Tools--->Driver Manager- (2).新建一个驱动,名称为phoenix(名称随意),选择phoenix的客户端驱动,驱动类如图所示 ...

  8. 使用js 设置组合快捷键

    使用js 设置组合快捷键 使用js设置快捷键的本质就是获得你要设置的这个键的keyCode 的值,如果要加ctrl,alt,shift,那么就添加一个ctrlkey,altKey,shiftKey来判 ...

  9. linux命令:ls

    命令格式: ls [OPTION]... [FILE]... 功能: 列出某个目录下的文件信息,默认列出当前目录.输出结果默认按字母顺序排列. 参数: -a, --all,-A, --almost-a ...

  10. Linux下TomcatVM参数修改:Native memory allocation (mmap) failed to map 3221225472 bytes for committing reserved memory.

    不可行的方法最初我直接修改catalina.sh, 将JAVA_OPTS变量加上了 -server -Xms1G -Xmx1G -XX:+UserG1GC最初看起来没啥问题,但是当服务器运行几天后,发 ...