美文网首页
iOS多线程(三):NSOperation

iOS多线程(三):NSOperation

作者: MirL | 来源:发表于2019-03-23 23:27 被阅读0次

    NSOperation是基于GCD的面向对象封装,在各大开源库里面我们常常看到它的身影。它的使用很简单易懂,基本上你点进Api就会用了,本文就最常用的功能进行讲解,更多的多线程原理还是看本系列文章的GCD部分。

    一、NSBlockOperation和NSInvocationOperation

    这两个类都是NSOperation的子类,它们的区别可能就是一个是用block回调,一个是用NSInvocation 回调,我们通常直接使用的也是这两个类,下面代码示意如何创建任务:

    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{}];
    
    NSInvocationOperation *invocationOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(respondsToOperation:) object:nil];
    
    

    都不用多说了,这就是两个任务,非常简单,当然,它还有一系列的方法表示状态:executingfinishedcancelled,以及开启和取消:startcancel,和NSThread一样有main方法可重写。

    二、NSOperationQueue 队列

    和GCD一样,NSOperation保留了队列的概念,但是没有具体的并行串行的概念了,但是我们可以实现它。

    先来看这样一段代码:

    NSLog(@"主线程开始");
    
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任务0 %@", [NSThread currentThread]);
    }];
    for (int i = 1; i < 5; i++) {
        [blockOperation addExecutionBlock:^{
            NSLog(@"任务%d: %@", i, [NSThread currentThread]);
            [NSThread sleepForTimeInterval:3];
        }];
    }
    [blockOperation start];
    
    NSLog(@"主线程结束");
    
    主线程开始
    任务3: <NSThread: 0x600000276080>{number = 5, name = (null)}
    任务2: <NSThread: 0x604000465740>{number = 4, name = (null)}
    任务1: <NSThread: 0x604000465700>{number = 3, name = (null)}
    任务0 <NSThread: 0x600000077300>{number = 1, name = main}
    任务4: <NSThread: 0x600000077300>{number = 1, name = main}
    主线程结束
    

    上机打印出来的效果来看,这些任务是并行执行的,但是会阻塞主线程直到任务全部都执行完成。显然这不能满足我们的全部需求,所以我们把任务加入队列试试(加入队列任务自动执行):

    NSLog(@"主线程开始");
    
    NSOperationQueue *queue = [NSOperationQueue new];
    
    NSBlockOperation *blockOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任务0 %@", [NSThread currentThread]);
    }];
    
    for (int i = 1; i < 5; i ++) {
        [blockOperation addExecutionBlock:^{
            NSLog(@"任务%d %@", i, [NSThread currentThread]);
        }];
    }
    
    [queue addOperation:blockOperation];
    
    //[blockOperation waitUntilFinished];
    
    NSLog(@"主线程结束");
    
    主线程开始
    主线程结束
    任务0 <NSThread: 0x600000475c40>{number = 3, name = (null)}
    任务1 <NSThread: 0x600000475f80>{number = 5, name = (null)}
    任务4 <NSThread: 0x600000475ec0>{number = 4, name = (null)}
    任务3 <NSThread: 0x600000475c40>{number = 3, name = (null)}
    任务2 <NSThread: 0x600000475f80>{number = 5, name = (null)}
    

    从打印结果来看,这是并行队列+异步任务,这基本满足我们后台执行耗时任务的需求了。

    从打印结果来看,这是并行队列+异步任务,这基本满足我们后台执行耗时任务的需求了。

    你们应该也注意到了我注释了一句代码[blockOperation waitUntilFinished];,现在将它打开,运行得到的结果和方法的名字一样,它会阻塞当前线程直到任务全部结束,当然NSOperationQueue也有这么一个方法:waitUntilAllOperationsAreFinished

    maxConcurrentOperationCount

    最大并发数,通过设置这个我们可以有效的控制并发任务的数量,从而对性能进行有效的控制。

    三、addDependency 添加任务依赖

    我们给NSOperation添加依赖的目的,主要是实现串行队列的效果。

    NSLog(@"主线程开始");
    
    NSOperationQueue *queue = [NSOperationQueue new];
    
    NSBlockOperation *operation0 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任务1: %@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:1.0];
    }];
    NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任务2: %@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:1.0];
    }];
    NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任务3: %@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:1.0];
    }];
    NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"任务4: %@", [NSThread currentThread]);
        [NSThread sleepForTimeInterval:1.0];
    }];
    
    [operation1 addDependency:operation0];
    [operation2 addDependency:operation1];
    [operation3 addDependency:operation2];
    //不要添加相互依赖。理论上不管任务在任何队列都可以添加依赖,不过不建议这么做。
    
    [queue addOperations:@[operation0, operation1, operation2, operation3] waitUntilFinished:YES];
    
    NSLog(@"主线程结束");
    
    主线程开始
    任务1: <NSThread: 0x604000474780>{number = 3, name = (null)}
    任务2: <NSThread: 0x6040004747c0>{number = 4, name = (null)}
    任务3: <NSThread: 0x604000474780>{number = 3, name = (null)}
    任务4: <NSThread: 0x6040004747c0>{number = 4, name = (null)}
    主线程结束
    

    实验证明,达到了我们预期的效果,任务1到任务4都是串行执行的,并且addOperations: waitUntilFinished:方法若第二个参数为YES,会阻塞主线程。

    写在后面

    NSOperation的用法不见得有GCD简洁,但它符合面向对象的编程思想,而且便于在我们的业务代码中穿梭,所以它的使用场景还是比较多的,没什么难点可言,本文列举的用法已经可言解决大多数的场景了,如果想多了解,直接看一遍苹果官网的API就OK了?。

    相关文章

      网友评论

          本文标题:iOS多线程(三):NSOperation

          本文链接:https://www.haomeiwen.com/subject/bezevqtx.html