iOS-多线程之NSOperation

继之前的NSThread、GCD,今天学习下NSOperation。NSOperation是个抽象类,并不直接实现多线程编程的能力,必须使用它的子类,配合使用NSOperationQueue队列实现多线程编程。
  • NSInvocationOperation
    - (通过initWithTarget:执行任务)
  • NSBlockOperation
    - (通过block执行任务)
  • 自定义子类继承自NSOperation,实现内部相应的方法
    - (通过重写父类的方法,执行任务)
NSInvocationOperation 的运用
// 通过 NSInvocationOperation 创建任务
-(void)NSInvocationOperation {
    // 创建任务
    NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(do_method) object:nil];
    // 开始任务
    [operation start];
}

-(void)do_method {
    NSLog(@"---任务01---%@",[NSThread currentThread]);
}

总结:默认主线程执行,不开启新线程


NSBlockOperation 的运用
// 通过 NSBlockOperation 创建任务
-(void)NSBlockOperation {
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"---任务01---%@",[NSThread currentThread]);
    }];
    // 只要NSBlockOperation封装的操作数 > 1,就会异步执行操作
    // 追加额外的任务
    [operation addExecutionBlock:^{
        NSLog(@"---任务02---%@",[NSThread currentThread]);
    }];
    // 追加额外的任务
    [operation addExecutionBlock:^{
        NSLog(@"---任务03---%@",[NSThread currentThread]);
    }];
    // 开始队列任务
    [operation start];
}

这里写图片描述
总结:如果任务只有一条,不开启新线程,主线程执行;当添加额外的任务时,会开启新的线程去执行任务


自定义 NSOperation 的运用
需要在自定义的XMOperation文件中重写 - (void)main; 方法
// 将需要执行的任务方法main函数中,当外界调用自己实例的start方法时,执行该任务
-(void)main {
    NSLog(@"---我是自定义队列任务---%@",[NSThread currentThread]);
}

// 自定义 NSOperation
-(void)DIYOperation {
    // 自定义继承自 NSOperation 的任务
    XMOperation *operation = [[XMOperation alloc] init];
    // 开始任务(去实现自定义类方法中的main函数)
    [operation start];
}

这里写图片描述
总结:当调用 [operation start] 后执行 - (void)main; 方法


NSOperationQueue 的运用
-(void)operationQueue {
    // 创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    // 通过 NSInvocationOperation 创建任务
    NSInvocationOperation *opt = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(do_method) object:nil];
    // 通过 NSBlockOperation 创建任务
    NSOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"---任务02---%@",[NSThread currentThread]);
    }];
    // 添加任务到队列中
    [queue addOperation:operation];
    [queue addOperation:opt];
    // 直接向队列中添加任务
    [queue addOperationWithBlock:^{
        NSLog(@"---任务03---%@",[NSThread currentThread]);
    }];
}

这里写图片描述
总结:开启多条线程,并且并发执行任务


最大并发数的使用(maxConcurrentOperationCount)
-(void)maxConcurrentOperationCount {
    // 创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    // 确定最大并发数,当并发数为1时,是串行队列
    // 当并发数为n(n>1)时,是并发队列,每次并发执行n条任务
    queue.maxConcurrentOperationCount = 2;
    // 添加任务到队列中
    [queue addOperationWithBlock:^{
        NSLog(@"---任务01---%@",[NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"---任务02---%@",[NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"---任务03---%@",[NSThread currentThread]);
    }];
    [queue addOperationWithBlock:^{
        NSLog(@"---任务04---%@",[NSThread currentThread]);
    }];
}
  • 图片 01 (最大并发数为2)
    这里写图片描述
  • 图片 02 (最大并发数为1)
    这里写图片描述
    总结:当最大并发数为1时,开启新线程,但一般只会开启一条,因为此时是串行执行。见图片 01
    当最大并发数大于1时(n(n>1)),开启多条线程,并发执行n条任务。见图片 01

对任务添加依赖的运用(addDependency)
// 添加依赖
-(void)addDependency {
    // 创建队列
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    // 通过 NSBlockOperation 创建任务
    NSBlockOperation *opt1 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"---任务01---%@",[NSThread currentThread]);
    }];
    NSBlockOperation *opt2 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"---任务02---%@",[NSThread currentThread]);
    }];
    NSBlockOperation *opt3 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"---任务03---%@",[NSThread currentThread]);
    }];
    NSBlockOperation *opt4 = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"---任务04---%@",[NSThread currentThread]);
    }];
    // 添加依赖
    [opt3 addDependency:opt4]; // 线程opt3 需要在 opt4 执行完毕后执行
    [opt2 addDependency:opt3]; // 线程opt2 需要在 opt3 执行完毕后执行
    [opt1 addDependency:opt2]; // 线程opt1 需要在 opt2 执行完毕后执行
    // 添加任务到队列中
    [queue addOperation:opt1];
    [queue addOperation:opt2];
    [queue addOperation:opt3];
    [queue addOperation:opt4];
}

这里写图片描述
总结:开启新线程,但执行顺序受依赖的影响
为每条任务添加依赖,也可以实现串行队列


队列的状态
- 暂停(suspended = YES) 
- 执行(suspended = NO)
- 取消所有任务 (cancelAllOperations)
- 判断是否暂停 (isSuspended)
    if (self.queue.isSuspended) { // 队列处于暂停状态
        // 恢复队列,继续执行
        self.queue.suspended = NO;
    } else { // 队列处于正常状态
        // 暂停(挂起)队列,暂停执行
        self.queue.suspended = YES;
    }
    // 取消所有队列
    [self.queue cancelAllOperations];

线程之间的通信

线程之间的通信模板

// 线程之间的通信
-(void)communicateWithOperation {
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    [queue addOperationWithBlock:^{
        NSLog(@"---子线程任务---%@",[NSThread currentThread]);
        // 回到主线程执行任务
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            NSLog(@"---主线程任务---%@",[NSThread currentThread]);
        }];
    }];
}

这里写图片描述


利用NSOperationQueue在子线程下载图片,主线程显示图片

// 线程之间的通信实例
-(void)communicateWithOperationInstance {
    // 开辟一个子线程执行图片下载任务
    [[[NSOperationQueue alloc] init] addOperationWithBlock:^{
        // 图片的网络路径
        NSURL *url = [NSURL URLWithString:@"http://xxx.png"];

        // 加载图片
        NSData *data = [NSData dataWithContentsOfURL:url];

        // 生成图片
        UIImage *image = [UIImage imageWithData:data];

        // 回到主线程,添加图片
        [[NSOperationQueue mainQueue] addOperationWithBlock:^{
            self.imageView.image = image;
        }];
    }];
}

总结:多线程的学习就到这里了,NSThread、GCD、NSOperation 这三条多线程方法在iOS开发中运用还是比较频繁的,其中GCD的功能最多,可以实现单例,延迟执行,多线程遍历,线程群组,线程阻碍等等。对于任务的分段下载,既可以用GCD的群组,也可以用NSOperation的依赖来实现。最后说一句,学习,一定得去敲,得去写,进步才会快

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值