美文网首页
NSOperation

NSOperation

作者: 小圆菜陪你财务自由 | 来源:发表于2018-07-06 23:31 被阅读0次

    废话不多说,直奔主题,

    NSOperation 的核心概念:将"操作" 添加到 "队列"

    而 GCD  是将"任务"添加到 "队列"

    一、NSOperation的作用

    配合使用NSOperation和NSOperationQueue也能实现多线程编程

    二、NSOperation和NSOperationQueue实现多线程的具体步骤

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

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

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

    4、将取出的NSOperation封装的操作放到一条新线程中执行

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

    1、NSInvocationOperation

    2、NSBlockOperation

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

    四、NSOperationQueue的作用

    NSOperation可以调用start方法来执行任务,但默认是同步执行的

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

    五、GCD & NSOperation 对比

    GCD 在 iOS 4.0 推出,主要针对多核处理器做了优化的并发技术,是C语言的

        - 将"任务"[block]添加到 队列[串行/并发/主队列/全局队列] ,并且指定执行任务的函数[同步/异步]

        - 线程间的通讯  dispatch_get_main_queue()

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

            - 一次执行

            - 延迟执行

            - 调度组(在op中也可以做到,有点麻烦)

    NSOperation 在 iOS 2.0 推出的,苹果推出

        - 将操作[异步执行的任务] 添加到队列[并发队列],就会立刻异步执行

        - mainQueue

        - 提供了一些GCD 实现起来比较困难的功能

            - 最大并发线程

            - 队列的暂停/继续

            - 取消所有操作

            - 指定操作之间的依赖关系(GCD 用同步来实现)

    六、代码举例

    1、NSInvocationOperation 操作添加到队列

    /** 开启多个线程 不会顺序执行 --> GCD 并发队列,异步执行

    NSOperation 本质上是对 GCD  的面向对象的封装!

    - 队列:本质上 就是GCD的并发队列

    - 操作:异步执行任务

    */

    -(void)demo1{

        //1.队列

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

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

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

            //添加到队列

            [q addOperation:op];

        }

    }

    2,NSBlockOperation操作添加到队列

    //NSBlockOperation 所有代码都写在一起,便于维护

    -(void)demo2{

        //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,更简单的添加方式

    -(void)demo3{

        //1.队列 - > 队列如果每次分配会比较浪费

        //在实际开发中,会使用全局队列

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

        //2.添加操作

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

            [q addOperationWithBlock:^{

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

            }];

        }

    }

    4,队列中添加各种“操作”,只要是NSOperation 的子类,都可以添加到队列!

    -(void)demo4{

        //直接添加任务

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

            [self.opQueue addOperationWithBlock:^{

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

            }];

        }

        //block operation

        NSBlockOperation * op1 = [NSBlockOperation blockOperationWithBlock:^{

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

        }];

        [self.opQueue addOperation:op1];

        //invocation operation

        NSInvocationOperation * op2 = [[NSInvocationOperation alloc]initWithTarget:self selector:@selector(downloadImage:) object:@"invocation"];

        [self.opQueue addOperation:op2];

    }

    七、线程间通信

    -(void)demo5{

        [self.opQueue addOperationWithBlock:^{

            NSLog(@"耗时操作  %@",[NSThread currentThread]);

            //主线程更新 UI

            [[NSOperationQueue mainQueue] addOperationWithBlock:^{

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

            }];

        }];

    }

    八、通过maxConcurrentOperationCount设置最大并发数

    -(void)demo{

        //设置同时最大的并发操作数量

        //WIFI条件下: 5 至 6

        //流量条件下 : 2 到 3

        self.opQueue.maxConcurrentOperationCount = 2;

        //添加操作进队列

      /*

        从 iOS 8.0 开始,无论使用 GCD还是 NSOperation ,都会开启很多线程

        在 iOS 7.0 以前,GCD 通常只会开启 5  6条线程!

        目前线程多了说明:

            1.底层的现场池更大了,能够拿到的线程资源多了!

            2.多控制同时并发的现场数,要求就更高了!

        */

    //注意这不是执行完两个线程就结束了,而是两个两个的执行,直到20个操作执行完毕。

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

            [self.opQueue addOperationWithBlock:^{

                [NSThread sleepForTimeInterval:1.0];

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

            }];

        }

    }

    九、暂停&恢复&取消操作

    -(void)pause{

        //在设置队列的暂停属性时,并不会判断队列中是否有操作!

        //如果不希望用户产生困惑,可以提前做判断

        //判断队列中当前是否有操作

        if (self.opQueue.operationCount == 0){

            NSLog(@"没有操作!!!");

            return ;

        }

        if (self.opQueue.isSuspended) {//判断是否被挂起

            //在暂停的时候,队列中的操作数,是包含正在执行的操作!!

            NSLog(@"继续 %tu",self.opQueue.operationCount);

            self.opQueue.suspended = NO;

        }else{

            //再次继续运行的时候,如果之前执行的操作已经完成,队列中的操作数就只有未调度的了!!

            NSLog(@"暂停 %tu",self.opQueue.operationCount);

            self.opQueue.suspended = YES;

        }

    }

    //取消所有的操作,假设添加20个操作,执行到一定程度后,全部取消

    -(void)cancelAll{

        //提示: 取消操作,同样不会取消正在执行中的操作

        NSLog(@"取消所有!!!");

        //取消当下所有操作

        [self.opQueue cancelAllOperations];

    }

    十、添加依赖关系(addDependency)

    注意,不是队列添加依赖关系,而是操作添加依赖关系后把操作添加到队列中去

    // 依赖关系 可以跨队列指定!!!!

    -(void)dependecy{

        /**

        需求:从网上下载视频\完成之后解码\通知用户

        */

        //1.下载

        NSBlockOperation * op1 = [NSBlockOperation blockOperationWithBlock:^{

            [NSThread sleepForTimeInterval:1.2];

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

        }];

        //2.解码

        NSBlockOperation * op2 = [NSBlockOperation blockOperationWithBlock:^{

            [NSThread sleepForTimeInterval:2.0];

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

        }];

        //3.通知用户

        NSBlockOperation * op3 = [NSBlockOperation blockOperationWithBlock:^{

            NSLog(@"通知用户  -  %@",[NSThread currentThread]);

        }];

        //NSOperation 提供了依赖关系

        //NSOperation 的所有的操作都是异步执行的,但是为了建立任务之间的依赖,提供了dependency的功能

        //GCD中,通过同步任务来实现,也可以通过串行队列!

        [op2 addDependency:op1];//op2 依赖于 op1  也就是  op1 执行完毕 op2 开始执行

        [op3 addDependency:op2];

        // !!千万注意!!!:  不要循环依赖!!!!,一旦指定了循环依赖,队列就不能执行被循环依赖的操作了!!

        //不会造成死锁!  但是 以前的版本 会死锁!!

    //    [op1 addDependency:op3];

        [self.opQueue addOperations:@[op1,op2] waitUntilFinished:NO];

        //主线程通知用户

        [[NSOperationQueue mainQueue] addOperation:op3];

        NSLog(@"come here");

    }

    相关文章

      网友评论

          本文标题:NSOperation

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