您的位置:首页 > 运维架构

NSOperation的介绍

2015-10-27 23:51 399 查看
iOS开发多线程篇—NSOperation简单介绍

一、NSOperation简介

1. 简单说明

a. NSOperation的作用:

是OC语言中基于GCD的面向对象的封装,使用起来比GCD更加简单(面向对象);
提供了一些用GCD不好实现的功能,使用NSOperation不用关心线程以及线程的生命周期(苹果推荐使用)。

b. 配合使用NSOperation和NSOperationQueue实现多线程编程的具体步骤:

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

(2)然后将NSOperation对象添加到NSOperationQueue中

(3)系统会⾃动将NSOperationQueue中的NSOperation取出来

(4)将取出的NSOperation封装的操作放到⼀条新线程中执⾏

c. NSOperation的子类

NSOperation是一个抽象类,不能直接使用(方法没有实现),约束子类都具有共同的属性和方法,并不具备封装操作的能力,必须使⽤它的子类。

使用NSOperation⼦类的方式有3种:
(1)NSInvocationOperation

(2)NSBlockOperation

(3)自定义子类继承NSOperation,实现内部相应的⽅法

2. 具体说明

2.1 NSInvocationOperation子类不常用】

创建对象和执行操作:

 //创建操作对象,封装要执行的任务

 //NSInvocationOperation 封装操作

  NSInvocationOperation *operation=[[NSInvocationOperation alloc] initWithTarget:self selector:@selector(test)
object:nil];

//执行操作

   [operation start];

注意:操作对象默认在主线程中执行,只有添加到队列中才会开启新的线程。即默认情况下,如果操作没有放到队列中queue中,都是同步执行。只有将NSOperation放到一个NSOperationQueue中,才会异步执行操作,不常用!

2.2 NSBlockOperation子类

注意:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作。

创建对象和添加操作:

//创建NSBlockOperation操作对象

  NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{

      NSLog(@"NSBlockOperation1------%@",[NSThread currentThread]);

           }];

 //通过addExecutionBlock:方法添加更多的操作

 [operation addExecutionBlock:^{

     NSLog(@"NSBlockOperation2------%@",[NSThread
currentThread]);

           }];

[operation start];

打印结果:

2015-10-26 14:06:11.765 test1[7036:326837] NSBlockOperation1------<NSThread: 0x7f8628e074d0>{number = 1, name = main}

2015-10-26 14:06:11.767 test1[7036:326882] NSBlockOperation2------<NSThread: 0x7f8628e2ef10>{number = 2, name = (null)}

2.3 NSOperationQueue

NSOperation可以调⽤start⽅法来执⾏任务,但默认是同步执行的。

如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作。

也就是说添加操作到NSOperationQueue中,自动执行操作,自动开启线程。

添加操作到NSOperationQueue中的两种那个方法:
 - (void)addOperation:(NSOperation *)op;

- (void)addOperationWithBlock:(void (^)(void))block;

注意:系统自动将NSOperationqueue中的NSOperation对象取出,将其封装的操作放到一条新的线程中执行,这些任务是并行执行的。

提示:队列的取出是有顺序的,与打印结果并不矛盾。这就好比,选手A,B,C虽然起跑的顺序是先A,后B,然后C,但是到达终点的顺序却不一定是A,B在前,C在后。

下面使用for循环打印,可以更明显的看出任务是并发执行的。

代码示例:

//创建NSInvocationOperation对象,封装操作

   
NSInvocationOperation
*operation1=[[NSInvocationOperation

alloc]initWithTarget:self

selector:@selector(test1)

object:nil];

   
NSInvocationOperation
*operation2=[[NSInvocationOperation

alloc]initWithTarget:self

selector:@selector(test2)

object:nil];

   
//创建NSBlockOperation对象,封装操作

   
NSBlockOperation
*operation3=[NSBlockOperation

blockOperationWithBlock:^{

       
for (int
i=0; i<5; i++) {

           
NSLog(@"NSBlockOperation3--1----%@",[NSThread

currentThread]);

        }

    }];

    [operation3
addExecutionBlock:^{

       
for (int
i=0; i<5; i++) {

           
NSLog(@"NSBlockOperation3--2----%@",[NSThread

currentThread]);

        }

    }];

   
//创建NSOperationQueue

   
NSOperationQueue
* queue=[[NSOperationQueue

alloc]init];

   
//把操作添加到队列中

    [queue
addOperation:operation1];

    [queue
addOperation:operation2];

    [queue
addOperation:operation3];

}

-(void)test1

{

   
for (int
i=0; i<5; i++) {

       
NSLog(@"NSInvocationOperation1--%@",[NSThread

currentThread]);

    }

}

-(void)test2

{

   
for (int
i=0; i<5; i++) {

       
NSLog(@"NSInvocationOperation2--%@",[NSThread

currentThread]);

    }

}

打印结果:

二、NSOperation 和 GCD 的比较

1. GCD

a.     GCD是iOS4.0 推出的,主要针对多核cpu做了优化,是C语言的技术;

b.     GCD是将任务(block)添加到队列(串行/并行/全局/主队列),并且以同步/异步的方式执行任务的函数;

c.     GCD提供了一些NSOperation不具备的功能

     1)一次性执行

     2)延迟执行

     3)调度组

2.  NSOperation

a.     NSOperation是iOS2.0推出的,iOS4之后重写了NSOperation;

b.     NSOperation将操作(异步的任务)添加到队列(并发队列),就会执行指定的操作;

c.     NSOperation里提供了方便的操作:

1)最大并发数:同时执行的任务数。

比如,同时开3个线程执行3个任务,并发数就是3。

最大并发数的相关方法

- (NSInteger)maxConcurrentOperationCount;

- (void)setMaxConcurrentOperationCount:(NSInteger)cnt;

示例:

-(NSOperationQueue
*)queue {

    if(!_queue){

        _queue
=[[NSOperationQueue
alloc]
init];

       
//设置对大并发数

       
_queue.maxConcurrentOperationCount
= 3;

    }

    return
_queue;

}

2)队列的暂定/继续,;

// YES代表暂停队列,NO代表恢复队列。

- (void)setSuspended:(BOOL)b; 

- (BOOL)isSuspended;

3)取消队列的所有操作

- (void)cancelAllOperations;

提示:也可以调用NSOperation的- (void)cancel方法取消单个操作。

示例:

//暂停,暂停的是队列中还没有被运行的操作,正在运行的操作不能被暂停;

//当队列为暂停的时候,往队列中加入操作,也不会运行。

- (IBAction)pauseClick:(id)sender
{

   
NSLog(@"点击暂停");

    [self.queue

setSuspended:YES];

}

//继续

- (IBAction)resumeClick:(id)sender
{

   
NSLog(@"点击继续");

    [self.queue

setSuspended:NO];

}

//取消

- (IBAction)cancelClick:(id)sender
{

   
NSLog(@"点击取消");

    [self.queue

cancelAllOperations];

}

4)指定操作之间的依赖关系(GCD可以用同步实现)

a. NSOperation之间可以设置依赖来保证执行顺序,比如一定要让操作A执行完后,才能执行操作B,可以这么写:

// 操作B依赖于操作A

[operationB addDependency:operationA]; 

b. 可以在不同queue的NSOperation之间创建依赖关系。

c. 注意不能相互依赖,比如A依赖B,B依赖A。

示例:

-(void)demo{

   

NSBlockOperation
*op1 = [NSBlockOperation

blockOperationWithBlock:^{

       
//模拟耗时操作

        [NSThread

sleepForTimeInterval:arc4random_uniform(3)];

       
NSLog(@"1.登陆

%@",[NSThread

currentThread]);

    }];

   

NSBlockOperation
*op2 = [NSBlockOperation

blockOperationWithBlock:^{

        [NSThread

sleepForTimeInterval:arc4random_uniform(3)];

       
NSLog(@"2.扣费

%@",[NSThread

currentThread]);

    }];

   

NSBlockOperation
*op3 = [NSBlockOperation

blockOperationWithBlock:^{

        [NSThread

sleepForTimeInterval:arc4random_uniform(3)];

       
NSLog(@"3.下载

%@",[NSThread

currentThread]);

    }];

   

NSBlockOperation
*op4 = [NSBlockOperation

blockOperationWithBlock:^{

       
NSLog(@"4.UI更新

%@",[NSThread

currentThread]);

    }];

   

//添加操作依赖,要在操作放到队列之前。

   
//操作依赖可以跨队列设置。

    [op2
addDependency:op1];

    [op3
addDependency:op2];

    [op4
addDependency:op3];

    [self.queue

addOperations:@[op1,op2,op3]

waitUntilFinished:NO];

    [[NSOperationQueue

mainQueue]

addOperation:op4];

}

5)操作队列的优先级

设置NSOperation在queue中的优先级,可以改变操作的执行优先级。

操作的优先级,优先级高的操作不一定最先运行。

队列的优先级 ,优先级高的队列不一定比优先级低的队列先运行完,而是有更多的可能被执行到。

6)线程间通信:

子线程->主线程 

操作方式与GCD类似。

示例:

[self.queue addOperationWithBlock:^{

         //子线程:do something

    [[NSOperationQueue mainQueue] addOperationWithBlock:^{

         //主线程的任务,操作UI等

    }];

}];

此外:
有些操作任务如果在主线程完成,会严重的影响到用户体验,造成UI卡的现象。我们可以通过自定义NSOperation,新开线程,让加载图片的任务异步执行,来解决此问题。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息