iOS

iOS 多线程之NSOperation和NSOperationQ

2016-12-30  本文已影响35人  XieHenry

一、NSOperation简介

NSOperation 是对 GCD 的封装,完全面向对象。 NSOperation 和 NSOperationQueue分别对应 GCD 的任务和队列。

1.简单说明

NSOperation的作⽤:配合使用NSOperation和NSOperationQueue也能实现多线程编程。
NSOperation和NSOperationQueue实现多线程的具体步骤:

(1)先将需要执行的操作封装到一个NSOperation对象中。
(2)然后将NSOperation对象添加到NSOperationQueue中。
(3)系统会⾃动将NSOperationQueue中的NSOperation取出来。
(4)将取出的NSOperation封装的操作放到⼀条新线程中执⾏。
2.NSOperation的子类

NSOperation是个抽象类,并不具备封装操作的能力,必须使⽤它的子类。
使用NSOperation⼦类的方式有3种:

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

二、 使用方法

1.NSInvocationOperation类
- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //NSOperation:抽象类,不具备封装功能
    //创建操作对象,封装要执行的任务
    //NSInvocationOperation   封装操作
    NSInvocationOperation *operation=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test) object:nil];
    //执行操作
    [operation start];
 
}
-(void)test
{
    NSLog(@"NSThread---%@",[NSThread currentThread]);
}
打印结果1.png

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

2.NSBlockOperation类

例1:

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //创建NSBlockOperation操作对象
    NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"NSBlockOperation------%@",[NSThread currentThread]);
    }];
    //开启执行操作
    [operation start];
}
打印结果2.png

例2:

- (void)viewDidLoad
{
    [super viewDidLoad];
    
        //创建NSBlockOperation操作对象
        NSBlockOperation *operation=[NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"NSBlockOperation------%@",[NSThread currentThread]);
        }];
    
        //添加操作
        [operation addExecutionBlock:^{
            NSLog(@"NSBlockOperation1------%@",[NSThread currentThread]);
        }];
    
        [operation addExecutionBlock:^{
            NSLog(@"NSBlockOperation2------%@",[NSThread currentThread]);
        }];
    
        //开启执行操作
        [operation start];
}
打印结果2.2.png

总结:只要NSBlockOperation封装的操作数 > 1,就会异步执行操作

3.NSOperationQueue

NSOperationQueue的作⽤:NSOperation可以调⽤start⽅法来执⾏任务,但默认是同步执行的
如果将NSOperation添加到NSOperationQueue(操作队列)中,系统会自动异步执行NSOperation中的操作
添加操作到NSOperationQueue中,自动执行操作,自动开启线程

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //创建NSInvocationOperation对象,封装操作
    NSInvocationOperation *operation1=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test1) object:nil];
    NSInvocationOperation *operation2=[[NSInvocationOperation alloc]initWithTarget:self selector:@selector(test2) object:nil];
    //创建对象,封装操作
    NSBlockOperation *operation3=[NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"NSBlockOperation3--1----%@",[NSThread currentThread]);
    }];
    [operation3 addExecutionBlock:^{
        NSLog(@"NSBlockOperation3--2----%@",[NSThread currentThread]);
    }];
    
    //创建NSOperationQueue
    NSOperationQueue * queue=[[NSOperationQueue alloc]init];
    //把操作添加到队列中
    [queue addOperation:operation1];
    [queue addOperation:operation2];
    [queue addOperation:operation3];
}

-(void)test1
{
    NSLog(@"NSInvocationOperation--test1--%@",[NSThread currentThread]);
}

-(void)test2
{
    NSLog(@"NSInvocationOperation--test2--%@",[NSThread currentThread]);
}
打印结果3.png

总结:这里一共有四个任务,operation1和operation2分别有一个任务,operation3有两个任务。一共四个任务,开启了四条线程。通过任务执行的时间全部都是一样的可以看出,这些任务是并行执行的。

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

4.其他

NSOperation有一个非常实用的功能,那就是添加依赖。比如有 3 个任务:A: 从服务器上下载一张图片,B:给这张图片加个水印,C:把图片返回给服务器。这时就可以用到依赖了:

- (void)viewDidLoad
{
    [super viewDidLoad];
    
    //1.任务一:下载图片
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"下载图片 - %@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:5.0];
    }];
    
    //2.任务二:打水印
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"打水印   - %@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:5.0];
    }];
    
    //3.任务三:上传图片
    NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"上传图片 - %@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:5.0];
    }];
    
    //4.设置依赖
    [operation2 addDependency:operation1];      //任务二依赖任务一
    [operation3 addDependency:operation2];      //任务三依赖任务二
    
    //5.创建队列并加入任务
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperations:@[operation3, operation2, operation1] waitUntilFinished:NO];
}

注意:不能添加相互依赖,会死锁,比如 A依赖B,B依赖A。
可以使用removeDependency来解除依赖关系。
可以在不同的队列之间依赖,反正就是这个依赖是添加到任务身上的,和队列没关系。

上一篇下一篇

猜你喜欢

热点阅读