NSOperation是基于GCD的一套多线程实现方案,和GCD一样,线程的生命周期是由系统来自动管理的,不用像NSThread和Pthread一样让程序员手动管理。相对于GCD来说,它更加地面向对象,并且比GCD多了一些更加简单实用的功能,另外,由于它的API是纯OC的,深受广大程序员喜爱,实用频率很高。

NSOperation主要和NSOperationQueue配合使用实现多线程,一般步骤如下:

1.先将需要执行的操作封装到一个NSOperation对象中;

2.然后将NSOperation对象添加到NSOperationQueue中;

3.系统会自动将NSOperationQueue中的NSOperation取出来;

4.将取出的NSOperation放到一条线程中执行。

注意:NSOperation是一个抽象类,并不具备封装操作的能力,必须使用它的子类。使用NSOperation子类的方式有如下三种:

1.NSInvocationOperation

2.NSBlockOperation

3.自定义子类继承NSOperation,实现内部相应的方法。

我们首先来看前两种:

一、NSOperation:

 - (void)viewDidLoad {
[super viewDidLoad];
[self invocationOperation];
} -(void)invocationOperation
{ // 1.创建操作对象,封住需要执行的任务
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil]; // 2.执行操作(默认情况下,如果操作没有放到操作队列中,同步执行)
[operation start];
} -(void)download1
{
NSLog(@"下载1----%@",[NSThread currentThread]);
}

结果如下:

可以看出,默认情况下,如果操作没有放到操作队列中,会在主线程同步执行,只有讲NSOperation放到NSOperationQueue中才会异步执行。

二、NSBlockOperation

 - (void)viewDidLoad {
[super viewDidLoad];
[self blockOperation];
} - (void)blockOperation
{
NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"NSBlockOperation--下载1---%@",[NSThread currentThread]);
}]; [operation addExecutionBlock:^{
NSLog(@"NSBlockOperation--下载2---%@",[NSThread currentThread]);
}]; [operation addExecutionBlock:^{
NSLog(@"NSBlockOperation--下载3---%@",[NSThread currentThread]);
}];
[operation start];
}

结果如图:

我们会发现,NSBlockOperation当只有单个任务的时候,也是默认在主线程执行,当任务数大于1的时候,会开启子线程并发执行其它的操作

三、配合使用NSOperationQueue

 - (void)viewDidLoad {
[super viewDidLoad];
[self operationQueue];
} - (void)operationQueue
{
NSInvocationOperation *operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil];
NSInvocationOperation *operation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download2) object:nil];
NSInvocationOperation *operation3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download3) object:nil];
NSBlockOperation *operation4 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"NSBlockOperation--1---%@",[NSThread currentThread]);
}];
[operation4 addExecutionBlock:^{
NSLog(@"NSBlockOperation--2---%@",[NSThread currentThread]);
}];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
[queue addOperation:operation4];
}
-(void)download1
{
NSLog(@"下载1----%@",[NSThread currentThread]);
}
-(void)download2
{
NSLog(@"下载2----%@",[NSThread currentThread]);
}
-(void)download3
{
NSLog(@"下载3----%@",[NSThread currentThread]);
}

结果如下

可以看出,只要是添加到NSOperationQueue中的操作,系统都会自动为我们开启子线程来执行,并且是并发无序的执行,和添加的顺序无关。

然而有些时候我们需要明确地指定操作的顺序,我们可以在NSOperation之间设置依赖来保证执行顺序。

比如操作1要在操作2后面执行,可以这么写:[operation1 addDependency:operation2] 意思是operation1依赖于operation2,也就是operation1要在operation2后面执行

上代码验证下:

 - (void)viewDidLoad {
[super viewDidLoad];
[self operationQueue];
} - (void)operationQueue
{
NSInvocationOperation *operation1 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download1) object:nil];
NSInvocationOperation *operation2 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download2) object:nil];
NSInvocationOperation *operation3 = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(download3) object:nil];
NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[operation3 addDependency:operation1];
[operation1 addDependency:operation2];
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
}
-(void)download1
{
NSLog(@"下载1----%@",[NSThread currentThread]);
}
-(void)download2
{
NSLog(@"下载2----%@",[NSThread currentThread]);
}
-(void)download3
{
NSLog(@"下载3----%@",[NSThread currentThread]);
}

结果如下:

操作顺序Operation2->Operation1->Operation3,完全正确,其实就是谁依赖谁,谁就在它的后面执行

另外也可以在不同queue的NSOperation之间设置依赖

操作顺序:4->3->2->1 其余两个并发执行

下面列出了NSOperationQueue的一些属性和方法:

1.- (void)cancelAllOperations 取消队列的所有操作。PS:也可以调用NSOperation的-(void)cancel方法取消单个操作

2.@property (getter=isSuspended) BOOL suspended;YES表示暂停队列,NO表示回复队列

3.@property NSInteger maxConcurrentOperationCount;表示最大并发数,一般不大于5

四、自定义NSOperation

当将自定义的NSOperation添加到NSOperationQueue的时候,系统会调用NSOperation的-(void)main方法,所以我们只要重写这个方法实现相应的实现即可。

 -(void)main
{
@autoreleasepool { // 异步线程无法访问主线程的自动释放池,需要自己添加
if (self.isCancelled) return;// 时刻监听操作是否取消,若取消就返回
NSURL *url = [NSURL URLWithString:self.matchUrl];
if (self.isCancelled) return;
NSData *data = [NSData dataWithContentsOfURL:url];
if (self.isCancelled) return;
UIImage *image = [UIImage imageWithData:data];
if ([_delegate respondsToSelector:@selector(operation:finshedDownloadImage:)]) {
dispatch_async(dispatch_get_main_queue(), ^{// 在主线程更新UI
[self.delegate operation:self finshedDownloadImage:image];
});
}
}
}

注意由于子线称无法访问主线程的自动释放池,所以需要自己添加。

下面是个小Demo截图,自定义NSOperation实现图片的异步下载,以及避免重复下载同一张图片

iOS多线程--NSOperation的更多相关文章

  1. iOS 多线程 NSOperation、NSOperationQueue

    1. NSOperation.NSOperationQueue 简介 NSOperation.NSOperationQueue 是苹果提供给我们的一套多线程解决方案.实际上 NSOperation.N ...

  2. iOS多线程 NSOperation的用法

    上一篇写了 GCD 的使用,接下来就了解一下 NSOperation ,NSOperation是苹果对 GCD 的 OC 版的一个封装,但是相对于GCD来说可控性更强,并且可以加入操作依赖. NSOp ...

  3. iOS多线程--NSOperation 浅显易懂

    NSOperation是基于GCD的一套多线程实现方案,和GCD一样,线程的生命周期是由系统来自动管理的,不用像NSThread和Pthread一样让程序员手动管理.相对于GCD来说,它更加地面向对象 ...

  4. iOS多线程---NSOperation介绍和使用

    1.  NSOperation实现多线程编程,需要和NSOperationQueue一起使用. (1)先将要执行的操作封装到NSOperation中 (2)将NSOperation对象添加到NSOpe ...

  5. IOS 多线程 NSOperation GCD

    1.NSInvocationOperation NSInvocationOperation * op; NSOperationQueue * que = [[NSOperationQueuealloc ...

  6. iOS多线程---NSOperation的常用操作

    1.最大并发数: - (NSInteger)maxConcurrentOperationCount;- (void)setMaxConcurrentOperationCount:(NSInteger) ...

  7. iOS多线程编程

    废话不多说,直接上干货.先熟悉一下基本知识,然后讲一下常用的两种,NSOperation和GCD. 一.基础概念 进程: 狭义定义:进程是正在运行的程序的实例(an instance of a com ...

  8. iOS GCD NSOperation NSThread等多线程各种举例详解(拷贝)

    2年多的iOS之路匆匆而过,期间也拜读来不少大神的博客,近来突然为自己一直做伸手党感到羞耻,是时候回馈社会.回想当年自己还是小白的时候,照着一些iOS多线程教程学,也只是照抄,只知其然.不知其所以然. ...

  9. iOS 多线程学习笔记 —— NSOperation

    本文复制.参考自文章:iOS多线程编程之NSOperation和NSOperationQueue的使用 ,主要为了加强个人对知识的理解和记忆,不做他用.原作者声明: 著作权声明:本文由http://b ...

随机推荐

  1. JDK源码重新编译——支持eclipse调试JDK源码--转载

    最近在研究jdk源码,发现debug时无法查看源码里的变量值. 因为sun提供的jdk并不能查看运行中的局部变量,需要重新编译一下rt.jar. 下面这六步是编译jdk的具体步骤: Step 1:   ...

  2. java 异常架构图

    cu 红色为检查异常,就是eclipse要提示你是try catch 还是throws. 非检查异常,就是/0,nullpointexception,数据越界访问indexOfOutBounds 异常 ...

  3. How to Kill All Processes That Have Open Connection in a SQL Server Database[关闭数据库链接 最佳方法] -摘自网络

    SQL Server database administrators may frequently need in especially development and test environmen ...

  4. MVC client validation after PartialView loaded via Ajax MVC3中 弹出 Dialog时候 提交的时候 使用 Jquery 不验证 form表单 的解决办法

    I came across this scenario whereby my main View uses Ajax posts to retrieve PartialViews and delive ...

  5. C# WinForm修改Panel边框颜色

    private void panel1_Paint(object sender, PaintEventArgs e) { ControlPaint.DrawBorder(e.Graphics, thi ...

  6. Sql FAQ

    1.查询结果根据条件翻译成其他值 then '及格' else '不及格' end from S_STUDENT then '及格' else '不及格' end from S_STUDENT 2.s ...

  7. 通过Response.Flush()实现IE下载失败的问题

    通过Response.Flush()实现对服务端文件的下载时,会失败,不能正常弹出IE下载框,经过测试发现需要进行如下设置后即可解决. 进入 [工具]--->[Internet选项]---> ...

  8. excel多个文件合并

    多个excel文件合并成一个需要用ms office wps是不行的 1.将所有文件放在一个文件夹里 2.在文件夹里新建一个空的excel打开 右键sheet点击查看代码->输入下面代码-> ...

  9. 算法基础:最大递减数问题(Golang实现)

    给出一个非负整数,找到这个非负整数中包括的最大递减数.一个数字的递减数是指相邻的数位从大到小排列的数字. 如: 95345323,递减数有:953,95,53,53,532,32, 那么最大的递减数为 ...

  10. ThinkPHP3.1 常量参考

    预定义常量 常量 说明 URL_COMMON=0 普通模式 URL URL_PATHINFO=1 PATHINFO URL URL_REWRITE=2 REWRITE URL URL_COMPAT=3 ...