NSOperation

2018-07-06  本文已影响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");

}

上一篇下一篇

猜你喜欢

热点阅读