线程探索三-NSOperation

本文属于多线程系列:
多线程探索一-概念
多线程探索二-GCD
多线程探索三-NSOperation
多线程探索四-锁

概念

NSOperation是APPLE推出的基于 GCD 封装的一套面向对象的API,接口更加简洁,上手更加方便。
优点

  1. 可以直接设置最大并发量
  2. 可以设置operation的执行顺序
  3. 可以通过KVO监听任务的状态
  4. 可以通过添加 completionBlock 在任务结束后做一些处理

API

NSOperation

NSOperation是一个抽象类,无法直接使用。系统提供了两个子类的实现,可以直接上手,当然也可以自己继承定制operation。

截屏2021-08-22 下午10.25.38.png

1. NSInvocationOperation

非并发的operation,通过 target selector添加任务

2. NSBlockOperation

并发的operation,通过添加block添加并发任务,可以在一个opertation中添加多个block并发执行。
当所有的block都执行完成后,operation会自动finish.

测试发现
+ blockOperationWithBlock: 添加的任务 一般在当前线程执行
- addExecutionBlock: 有开启新线程的能力

3. custom Operation

自定义operation, 抽象类提供了几个方法 官方文档 其实超级详细

非并发的operation
main 一般推荐把task内容放在这里, 如果需要访问operation里的数据,记得保证线程安全

并发的operation 至少需要重写以下几个方法

start       此方法默认在当前线程,所以如果需要异步开启任务,需要在这里开启新线程 去执行任务 
asynchronous    当前是同步还是异步的
executing       当前operation是否正在执行
finished        当前operation是否执行完

finished这个状态在操作完成后请及时设置为YES,因为NSOperationQueue所管理的队列中,只有isFinished为YES时才将其移除队列,这点在内存管理和避免死锁很关键。

下面是个demo


#import "CustomOperation.h"

@interface CustomOperation()
@property (assign, nonatomic, getter = isExecuting) BOOL executing;
@property (assign, nonatomic, getter = isFinished) BOOL finished;
@end

@implementation CustomOperation

@synthesize executing = _executing;
@synthesize finished = _finished;

- (void)main {
    if (self.isCancelled) {
        return;
    }
    NSLog(@"begin executing %@ at %@", NSStringFromSelector(_cmd), [NSThread currentThread]);

    for (int i = 0; i < 10; i++) {
        if (self.isCancelled) {
            self.executing = NO;
            self.finished = NO;
            return;
        }
        NSLog(@"%@ at thread %@", NSStringFromClass([self class]), [NSThread currentThread]);
    }
    self.executing = NO;
    self.finished = YES;
    NSLog(@"finish executing %@ at %@", NSStringFromSelector(_cmd), [NSThread currentThread]);
}

- (void)start {
    @synchronized (self) {

        if (self.isCancelled) {
            return;
        }
        [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil]; //默认start在主线程,如果想开启子线程,就需要手动开始子线程执行
    //    [self main];
        self.executing = YES;
    }
}

- (void)cancel {
    @synchronized (self) {
        if (self.isFinished) {
            return;
        }
        [super cancel];
        if (self.isExecuting) {
            self.executing = NO;
        }
        if (!self.isFinished) {
            self.finished = YES;
        }
    }
}



- (BOOL)isAsynchronous {
    return YES;
}


// custom 通知KVO
- (void)setExecuting:(BOOL)executing {
    [self willChangeValueForKey:@"isExecuting"];
    _executing = executing;
    [self didChangeValueForKey:@"isExecuting"];
}

- (void)setFinished:(BOOL)finished {
    [self willChangeValueForKey:@"isFinished"];
    _finished = finished;
    [self didChangeValueForKey:@"isFinished"];
}

@end

KVO

isCancelled - read-only
isAsynchronous - read-only
isExecuting - read-only
isFinished - read-only
isReady - read-only
dependencies - read-only
queuePriority - readable and writable
completionBlock - readable and writable

NSoperationQueue

NSoperationQueue 和 NSOperation配合使用
NSoperationQueue内的对象是线程安全的
NSoperationQueue同时支持KVC和KVO

operations - read-only
operationCount - read-only
maxConcurrentOperationCount - readable and writable
suspended - readable and writable
name - readable and writable

NSOperation 可以设置Dependency 但是 dependency的设置需要在operation 添加到 operation queue 之前才能生效。dependency可以跨queue。 当queue的maxConcurrentOperationCount == 1 的时候 无效。

NSOperationQueuePriority 默认是normal,当有需要时并且在没有设置dependency的情况下使用。 (不过本人尝试后发现并没有什么效果 ~~)

addBarrierBlock:

此方法是iOS13以后添加的,用法类似dispatch_barrier,详情可以参考上篇 多线程探索二-GCD ,可以用于在queue里前面添加的task执行后做一些同一个处理。

tips: 建议研究下SDWebImage,看下人家是怎么用NSOperation的。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • 前言 iOS多线程有四种:pthread(最古老的),NSThread,NSOperation,GCD 一、进程和...
    GitHubPorter阅读 2,790评论 0 3
  • 猜想runloop内部是如何实现的?一般来讲,一个线程一次只能执行一个任务,执行完成后线程就会退出。如果我们需要一...
    笔笔请求阅读 3,169评论 0 0
  • 什么是线程、多线程? 在学习iOS多线程应用之前,我们先来学习一下什么是线程? 线程是操作系统能够进行运算调度的最...
    浪的出名阅读 2,563评论 0 1
  • 讲多线程这个话题,就免不了先了解多线程相关的技术概念。本文涉及到的技术概念有CPU、进程、线程、同异步、队列等概念...
    jackyshan阅读 9,196评论 2 26
  • 16宿命:用概率思维提高你的胜算 以前的我是风险厌恶者,不喜欢去冒险,但是人生放弃了冒险,也就放弃了无数的可能。 ...
    yichen大刀阅读 11,281评论 0 4