NSOperation 与 NSOperationQueue 解析

于如何自定义NSOperation还有疑惑,那么下面内容,可以帮助你解决这个问题。如果对于NSOperation的相关基础知识,还有疑问的,那么,你可以点击上面那篇文章,可以帮助你解惑。

NSOperation 与 NSOperationQueue 解析

为什么要使用NSOperation
NSOperation提供任务的封装,NSOperationQueue顾名思义,提供执行队列,可以自动实现多核并行计算,自动管理线程的生命周期,如果是并发的情况,其底层也使用线程池模型来管理,基本上可以说这两个类提供的功能覆盖了GCD,并且提供了更多可定制的开发方式,开发者可以按需选择。
NSOperation把封装好的任务交给不同的NSOperationQueue即可进行串行或并发队列的执行。
通常情况下,任务会交给NSOperation类的一个方法,main或者start方法,所以我们要自定义继承NSOperation类的话,需要重写相关方法。

NSOperation 常用属性和方法


复制代码

// 对于并发的Operation需要重写改方法
- (void)start;

// 非并发的Operation需要重写该方法
- (void)main; 

相关属性


// 任务是否取消(只读) 自定义子类,需重写该属性
@property (readonly, getter=isCancelled) BOOL cancelled;

// 可取消操作,实质是标记 isCancelled 状态,自定义子类,需利用该方法标记取消状态
- (void)cancel;

// 任务是否正在执行(只读),自定义子类,需重写该属性
@property (readonly, getter=isExecuting) BOOL executing;

// 任务是否结束(只读),自定义子类,需重写该属性
// 如果为YES,则队列会将任务移除队列
@property (readonly, getter=isFinished) BOOL finished;

// 判断任务是否为并发(只读),默认返回NO
// 自定义子类,需重写getter方法,并返回YES
@property (readonly, getter=isAsynchronous) BOOL asynchronous;

// 任务是否准备就绪(只读)
// 对于加入队列的任务来说,ready为YES,则表示该任务即将开始执行
// 如果存在依赖关系的任务没有执行完,则ready为NO
@property (readonly, getter=isReady) BOOL ready; 

操作同步


// 添加任务依赖
- (void)addDependency:(NSOperation *)op;

// 删除任务依赖
- (void)removeDependency:(NSOperation *)op;

typedef NS_ENUM(NSInteger, NSOperationQueuePriority) {
   NSOperationQueuePriorityVeryLow = -8L,
   NSOperationQueuePriorityLow = -4L,
   NSOperationQueuePriorityNormal = 0,
   NSOperationQueuePriorityHigh = 4,
   NSOperationQueuePriorityVeryHigh = 8
};
// 任务在队列里的优先级
@property NSOperationQueuePriority queuePriority;

// 会在当前操作执行完毕时调用completionBlock
@property (nullable, copy) void (^completionBlock)(void);

// 阻塞当前线程,直到该操作结束,可用于线程执行顺序的同步
- (void)waitUntilFinished; 

NSOperationQueue 常用属性和方法

添加任务


// 向队列中添加一个任务
- (void)addOperation:(NSOperation *)op;

// 向队列中添加操作数组,wait 标志是否阻塞当前线程直到所有操作结束
- (void)addOperations:(NSArray<NSOperation *> *)ops waitUntilFinished:(BOOL)wait;

//  向队列中添加一个 block 类型操作对象。
- (void)addOperationWithBlock:(void (^)(void))block; 

相关属性


// 获取队列中所有任务(只读)
@property (readonly, copy) NSArray<__kindof NSOperation *> *operations;

// 获取队列中任务数量(只读)
@property (readonly) NSUInteger operationCount;

// 队列支持的最大任务并发数
@property NSInteger maxConcurrentOperationCount;

// 队列是否挂起
@property (getter=isSuspended) BOOL suspended;

// 队列名字
@property (nullable, copy) NSString *name 

相关方法


// 取消队列中所有的任务
- (void)cancelAllOperations;

// 阻塞当前线程,直到所有任务完成
- (void)waitUntilAllOperationsAreFinished;

// 类属性,获取当前队列
@property (class, readonly, strong, nullable) NSOperationQueue *currentQueue;

// 类属性,获取主队列(并发数为1)
@property (class, readonly, strong) NSOperationQueue *mainQueue; 

自定义NSOperation子类

在官方文档中支出,自定义NSOperation子类有两种方式,并发和非并发。 非并发只需要继承NSOperation后,实现main方法即可。而并发的操作相对较多一点,下面将详细描述。

非并发的NSOperation子类

官方文档描述:
Methods to Override
For non-concurrent operations, you typically override only one method: main
Into this method, you place the code needed to perform the given task.

在官方文档中指出,非并发任务,直接将需要执行的任务放在main方法中,然后直接调用即可。 这样直接调用main方法会存在一个问题,由于没有实现finished属性,所以获取finished属性时,只会返回NO,而且任务加入到队列后,不会被删除,另外任务执行完后,回调也不会被执行,所以最好不要只实现一个main方法来使用。 而且,其实也没有必要使用这种非并发的NSOperation子类,实在想不出有什么场景需要来用它,毕竟不方便。

并发的NSOperation子类

官方文档描述:
Methods to Override
If you are creating a concurrent operation, you need to override the following methods and properties at a minimum:
start
asynchronous
executing
finished

通过官方文档可以知道,实现并发的自定义子类,需要重写下面几个方法或属性:

  • start:把需要执行的任务放在start方法里,任务加到队列后,队列会管理任务并在线程被调度后,调用start方法,不需要调用父类的方法
  • asynchronous:表示是否并发执行
  • executing:表示任务是否正在执行,需要手动调用KVO方法来进行通知,方便其他类监听了任务的该属性
  • finished:表示任务是否结束,需要手动调用KVO方法来进行通知,队列也需要监听改属性的值,用于判断任务是否结束

相关代码:


@interface ZBOperation : NSOperation

@property (nonatomic, readwrite, getter=isExecuting) BOOL executing;
@property (nonatomic, readwrite, getter=isFinished) BOOL finished;

@end

@implementation ZBOperation
// 因为父类的属性是Readonly的,重载时如果需要setter的话则需要手动合成。
@synthesize executing = _executing;
@synthesize finished = _finished;

- (void)start {
    @autoreleasepool{
    self.executing = YES;
        if (self.cancelled) {
            [self done];
            return;
        }
        // 任务。。。
    }
    // 任务执行完成,手动设置状态
    [self done];
}

- (void)done {
    self.finished = YES;
    self.executing = NO;
}

#pragma mark - setter -- getter
- (void)setExecuting:(BOOL)executing {
    //调用KVO通知
    [self willChangeValueForKey:@"isExecuting"];
    _executing = executing;
    //调用KVO通知
    [self didChangeValueForKey:@"isExecuting"];
}

- (BOOL)isExecuting {
    return _executing;
}

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

- (BOOL)isFinished {
    return _finished;
}

// 返回YES 标识为并发Operation
- (BOOL)isAsynchronous {
    return YES;
}

// 调用类
- (void)congfigOperation {
    self.queue = [[NSOperationQueue alloc] init];
    [self.queue setMaxConcurrentOperationCount:2];

    self.zbOperation = [[ZBOperation alloc] init];
    [self.queue addOperation:self.zbOperation];
}` 

关于NSOperationNSOperationQueue的自定义子类的使用基本上描述完了,一些比较细节的东西,可以参考官方文档。

有关NSOperationNSOperationQueue的应用,我们可以阅读有关AFNetworkingSDWebImage的源码,源码中使用了大量的NSOperation操作。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 206,968评论 6 482
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 88,601评论 2 382
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 153,220评论 0 344
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 55,416评论 1 279
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 64,425评论 5 374
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,144评论 1 285
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,432评论 3 401
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,088评论 0 261
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 43,586评论 1 300
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,028评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,137评论 1 334
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,783评论 4 324
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,343评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,333评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,559评论 1 262
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,595评论 2 355
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,901评论 2 345

推荐阅读更多精彩内容