NSOperation与GCD

NSOperation 抽象类
    - NSInvocationOperation
    - NSBlockOperation
 NSOpeartionQueue

 * GCD 的核心概念:将任务(block)添加到队列,并且指定执行任务的函数
 * OP 的核心概念:将`操作`添加到`队列`

NSInvocationOperation(不常用)


// 将操作添加到队列 - 会异步执行操作!

- (void)opDemo1 {

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

    // start 会在当前线程执行 selector 方法,不会开启线程
//    [op start];

    // 队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    // 将操作添加到队列 - 会`异步`执行操作!
    [queue addOperation:op];
}

队列是一个并发队列

- (void)opDemo2 {
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    for (int i = 0; i < 100; ++i) {
        NSInvocationOperation *op = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@(i)];

        [queue addOperation:op];
    }
}
- (void)demo:(id)obj {
    NSLog(@"%@ %@", [NSThread currentThread], obj);
}

NSBlockOperation(常用)


任务在子线程异步并发执行

- (void)opDemo3 {
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];

    // 操作
    // 使用 block 所有的代码可以在一起,便于阅读和维护
    for (int i = 0; i < 10; ++i) {
        NSBlockOperation *op = [NSBlockOperation blockOperationWithBlock:^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        }];

        [queue addOperation:op];
    }
}

将任务加入到一个全局队列, 并且NSOperation的所有子类都可以加入, 异步执行

- (void)opDemo4 {
    for (int i = 0; i < 10; ++i) {
        [self.queue addOperationWithBlock:^{
            NSLog(@"%@ %d", [NSThread currentThread], i);
        }];
    }

    // BLOCK OPERATION
    // 所有的 NSOperation 的子类,都可以添加到队列中
    // 并且都是异步执行的!
    NSBlockOperation *blockOp = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"BLOCK --- %@", [NSThread currentThread]);
    }];
    [self.queue addOperation:blockOp];

    NSInvocationOperation *inOp = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(demo:) object:@"INVOCATION"];
    [self.queue addOperation:inOp];
}

线程间通讯

- (void)opDemo5 {
    [self.queue addOperationWithBlock:^{
        NSLog(@"耗时的操作... %@", [NSThread currentThread]);

        // 在主线程更新UI 
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            NSLog(@"更新 UI %@", [NSThread currentThread]);
        }];
    }];
}

NSOperation的高级用法

  • 最大并发数
- (void)demo {
    // 设置最大并发的操作数
    [self.queue setMaxConcurrentOperationCount:2];

    NSLog(@"start");
    for (int i = 0; i < 20; ++i) {
        [self.queue addOperationWithBlock:^{

            [NSThread sleepForTimeInterval:1.0];

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

// 执行结果是两个两个一起来

  • 暂停/继续
// 暂停继续
- (IBAction)pauseAndResume {

    // 如果队列是挂起的,再添加操作,也不会调度!
    // 判断队列中是否有操作
    if (self.queue.operationCount == 0) {
        NSLog(@"没有操作");
        return;
    }

    // setter = !getter
    // 挂起的是队列,不会影响正在执行的操作
    self.queue.suspended = !self.queue.isSuspended;

    // 如果队列中的操作没有执行完成,操作`计数`中是包含的
    if (self.queue.isSuspended) {
        NSLog(@"暂停 - %tu", self.queue.operationCount);
    } else {
        NSLog(@"继续 - %tu", self.queue.operationCount);
    }
}

执行结果: 暂停的是队列中的操作, 如果任务在线程中正在执行, 不会停止

  • 取消全部
- (IBAction)cancelAll {

    // 取消`队列`中没有调度的全部操作,如果正在执行的操作,不会被取消
    // 提示:如果要让正在执行的操作取消,需要自定义操作,系统提供的不行!
    NSLog(@"取消全部");
    [self.queue cancelAllOperations];
}

执行结果: 系统提供的无法取消线程中正在执行的操作, 只能取消队列中等待的操作.

  • 依赖关系(GCD中的依赖,可以用同步执行,barrier)
- (void)dependency {

    NSBlockOperation *op1 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"用户登录 %@", [NSThread currentThread]);
    }];
    NSBlockOperation *op2 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"付费 %@", [NSThread currentThread]);
    }];
    NSBlockOperation *op3 = [NSBlockOperation blockOperationWithBlock:^{

        NSLog(@"下载 %@", [NSThread currentThread]);
    }];
    NSBlockOperation *op4 = [NSBlockOperation blockOperationWithBlock:^{

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

    // 设置依赖关系 - 并发效率比GCD的串行队列要好!
    // 依赖关系,可以跨队列指定!
    // 付费需要在用户登录之后执行
    [op2 addDependency:op1];
    [op3 addDependency:op2];
    [op4 addDependency:op3];

    // waitUntilFinished NO 异步 YES 同步
    [self.queue addOperations:@[op1, op2, op3] waitUntilFinished:NO];

    // 向主队列添加操作
    [[NSOperationQueue mainQueue] addOperation:op4];

    NSLog(@"come here");
}

GCD与NSOperation对比

  • GCD

将任务(block)添加到队列(串行/并发/主队列),并且指定任务执行的函数(同步/异步)
GCD是底层的C语言构成的API
iOS 4.0 推出的,针对多核处理器的并发技术
在队列中执行的是由 block 构成的任务,这是一个轻量级的数据结构
要停止已经加入 queue 的 block 需要写复杂的代码
需要通过 Barrier 或者同步任务设置任务之间的依赖关系
只能设置队列的优先级
高级功能:
一次性 once
延迟操作 after
调度组

  • NSOperation

核心概念:把操作(异步)添加到队列(全局的并发队列)
OC 框架,更加面向对象,是对 GCD 的封装
iOS 2.0 推出的,苹果推出 GCD 之后,对 NSOperation 的底层全部重写
Operation作为一个对象,为我们提供了更多的选择
可以随时取消已经设定要准备执行的任务,已经执行的除外
可以跨队列设置操作的依赖关系
可以设置队列中每一个操作的优先级
高级功能:
最大操作并发数(GCD不好做)
继续/暂停/全部取消
跨队列设置操作的依赖关系

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章