iOS - 多线程(三) NSOperation讲解

2017-09-01  本文已影响18人  伦伦子_f7b3

NSOperation在ios2出来的,后来又基于GCD进行了重写,但是相对于GCD来说可控性更强,并且可以加入操作依赖。

NSOperation是一个抽象的基类,表示一个独立的计算单元,可以为子类提供有用且线程安全的建立状态,优先级,依赖和取消等操作。系统已经给我们封装了NSBlockOperation和NSInvocationOperation这两个实体类。使用起来也非常简单,不过我们更多的使用是自己继承并定制自己的操作。

NSOperation 和 GCD对比:

(1) GCD ,主要多核处理器优化的并发技术,是C语言的

    将任务(block)添加到队列(串行、并行、主队列、全局队列),并且要指定任务的同步、异步;

    线程间的通讯 dispatch_get_main_queue()

    提供了一些 NSOperation不具备的功能:

          一次执行(单例)

          延迟执行

          调度组(NSOperation 也可以做到,但是有点麻烦)

 (2)NSOperation 在iOS 2.0;苹果推出了GCD之后,对NSOperation 进行了重写

    将操作[异步执行的任务]添加到 【并发队列】,就会立刻异步执行,NSOperation需要配合NSOperationQueue使用

     提供了一个些GCD实现起来比较麻烦功能

             最大并发线程

             队列的暂停、继续

             取消所有线程

             线程依赖(线程A 的执行必须 依赖线程B)(GCD 同步实现!)



一. 首先对NSOperationQueue说明

         NSOperationQueue相当于GCD中的队列(dispatch_queue_t)。和GCD中的并发队列、串行队列略有不同的是:NSOperationQueue一共有两种队列:主队列、其他队列。其中其他队列同时包含了串行、并发功能。下边是主队列、其他队列的基本创建方法和特点。

        主队列: 凡是添加到主队列中的任务(NSOperation),都会放到主线程中执行;

                     通过 NSOperationQueue *queue = [NSOperationQueue mainQueue] 获取;

        其他队列(同时包含了:并发功能,非主队列):添加到这种队列中的任务(NSOperation),就会自动放到子线程中执行

                     通过NSOperationQueue *queue = [[NSOperationQueue alloc] init]获取;

那么对于其他队列如何像GCD一样控制串行执行和并行执行呢?     

这里有个关键参数maxConcurrentOperationCount,叫做最大并发数

maxConcurrentOperationCount默认情况下为-1,表示不进行限制,默认为并发执行。

当maxConcurrentOperationCount为1时,可以当作是串行队列,但是本质上其实还是并发队列,只是被限制了一次只能执行一个任务。

当maxConcurrentOperationCount大于1时,进行并发执行,当然这个值不应超过系统限制,即使自己设置一个很大的值,系统也会自动调整。




二. 两个系统提供的子类使用介绍 NSInvocationOperation ,NSBlockOperation


1.NSInvocationOperation使用(2.0就有了)

-(void)demo{

      //1.队列

         NSOperationQueue *q = [[NSOperationQueue  alloc]init];

        q.maxConcurrentOperationCount = 1;

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

           //创建操作任务

            NSInvocationOperation *op  = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downImage:) object:@(i)];

            //添加到队列

            [q addOperation:op];

        }

}


-(void)downImage:(id)objc{

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

}

输出结果:


分析:由于操作任务加入到其他队列中,该队列默认并发数为1,所以相当于串行队列,所以该队列中的任务会串行执行。但是为何不在同一个线程中执行?(疑问)。这里设置为1,效果只是相当于串行队列一样串行执行,但是NSOperationQueue *q = [[NSOperationQueue  alloc]init]本质上是异步并发队列,所以还是会开启多条线程,只是同一时间只能使用其中一条来执行任务而已。


2.NSBlockOperation使用(4.0才有)

-(void)demo{

          //1.队列

           NSOperationQueue *q = [[NSOperationQueue  alloc]init];

           //2.操作

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

                NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{

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

               }];

               //操作添加到队列

                [q addOperation:op];

      }

}

输出结果:

分析:由于操作任务加入到其他队列中,该队列默认并发数为默认值,所以为并发队列,所以该队列中的任务会并行执行




3.不使用NSOperation子类,直接使用NSOperationQueue添加任务


     -(void)demo{

               //1.队列

             NSOperationQueue *q = [[NSOperationQueue  alloc]init];

             //2.操作任务直接以block的形式添加到队列中

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

                    [q addOperationWithBlock:^{

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

                     }];

               }

        }

输出结果:

4.线程间通信

  

      -(void)demo6{

                 NSOperationQueue *q = [[NSOperationQueue  alloc]init];

                 [q addOperationWithBlock:^{

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

                         //主线程

                          [[NSOperationQueue mainQueue] addOperationWithBlock:^{

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

                          }];

                }];

       }

输入结果:


三.自定义实现一个NSOperation的子类

上一篇下一篇

猜你喜欢

热点阅读