NSOperation

NSOperation表示了一个独立的计算单元。作为一个抽象类,它给了它的子类一个十分有用而且线程安全的方式来建立状态、优先级、依赖性和取消等的模型。你可以使用系统提供的NSBlockOperationNSInvocationOperation方法来创建一个operation,也可以创建一个继承NSOperation抽象类的operation。

异步vs同步Operations

Operations分为同步和异步。创建的operations默认是一个同步的operation。如果你调用start方法启动一个operation,它会在当前线程执行,并且阻塞当前线程直到这个operation结束。另外,你可以把operations放入operation queue中。放入operation queue中的operations会另起一个线程调用start方法,因此会异步执行。当然你可以创建一个异步的operation,这需要重写很多方法,比较麻烦,建议是直接放入operation queue中。

NSOperation的状态

NSOperation包含了一个状态机来描述每一个操作的执行。

  • isReady 已经准备好执行
  • isExecuting 正在执行
  • isFinished 执行成功或取消
    这三种状态是相互独立的,同时只能是一个状态属性返回YES。这些状态由keypath的KVO通知决定。

NSOperation依赖性

如果某些operation需要按照一定的次序执行。则可以通过addDependency为相应的队列添加依赖。但是在添加依赖的时候要注意依赖循环,从而导致死循环。

NSOperation优先级

你可以通过operation的queuePriority来设置优先级,从而加快或者延迟queue中的operation的执行。默认的queuePriorityNSOperationQueuePriorityNormal

  • NSOperationQueuePriorityVeryLow
  • NSOperationQueuePriorityLow
  • NSOperationQueuePriorityNormal
  • NSOperationQueuePriorityHigh
  • NSOperationQueuePriorityVeryHigh

但是priority不能与dependency一起使用。添加了dependency的operation一定严格按照dependency的顺序执行。
同时你可以通过operation的qualityOfService来设置系统资源对operation的保障。高保障的operation的优先级大于低保障的operation的优先级。默认的保障等级是NSQualityOfServiceBackground。

  • NSQualityOfServiceUserInteractive
  • NSQualityOfServiceUserInitiated
  • NSQualityOfServiceUtility
  • NSQualityOfServiceBackground

NSOperation用法

首先介绍以下NSBlockOperation和NSInvocationOperation。代码如下:

- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view, typically from a nib.
    NSOperationQueue *queue = [[NSOperationQueue alloc] init];
    NSOperation *blkOperation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"blk start");
        [NSThread sleepForTimeInterval:3];
        NSLog(@"blk finished");
    }];
    blkOperation.queuePriority = NSOperationQueuePriorityHigh;
    blkOperation.qualityOfService = NSQualityOfServiceUserInitiated;
    NSMutableArray *arr = [NSMutableArray arrayWithArray:@[@1,@2]];
    NSOperation *invoOperation = [[NSInvocationOperation alloc] initWithTarget:self selector:@selector(doSomethingWithArr:) object:arr];
    NSLog(@"question");
    [queue addOperation:blkOperation];
    blkOperation.completionBlock = ^{
        NSLog(@"haha");
    };
    [NSThread sleepForTimeInterval:1];
    [blkOperation cancel];
    [queue addOperation:invoOperation];
    [blkOperation waitUntilFinished];
    NSLog(@"answer");

}

- (void)doSomethingWithArr:(NSMutableArray *)arr {
    NSLog(@"arr is %@ in invo",arr);

}

执行结果:

2018-01-05 09:13:31.205077+0800 NSOperationDemo[25280:6903063] question
2018-01-05 09:13:31.205314+0800 NSOperationDemo[25280:6903118] blk start
2018-01-05 09:13:32.206698+0800 NSOperationDemo[25280:6903116] arr is (
1,
2
) in invo
2018-01-05 09:13:34.209701+0800 NSOperationDemo[25280:6903118] blk finished
2018-01-05 09:13:34.209970+0800 NSOperationDemo[25280:6903063] answer
2018-01-05 09:13:34.209981+0800 NSOperationDemo[25280:6903116] haha

当blkOperation被加入到queue时,这个blkOperation才会被执行。加入queue中的operations是并发执行的。所以invoOperation会同时和blkOperation一起执行。不过由于queue遵循FIFO原则,所以一般会blkOperation先于invoOperation执行。由于blkOperation的cancel在1s后执行,此时由于blkOperation已经在执行,所以无法取消。waitUntilFinished必须是在加入queue后才能执行,不然会死锁。waitUntilFinished后面的代码会在当前operation执行完之后才会执行。completionBlock表示这个opertion执行完之后做的处理。

接下来介绍一下自定义并发的operation。代码如下:

@interface AWOperation() {
BOOL executing;
BOOL finished;
}

@end

@implementation AWOperation

- (instancetype)init {
    if (self = [super init]) {
        executing = NO;
        finished = NO;
    }
    return self;
}

- (void)start {
    if (self.isCancelled) {
        [self willChangeValueForKey:@"isFinished"];
        finished = YES;
        [self didChangeValueForKey:@"isFinished"];
        return;
    }

    [self willChangeValueForKey:@"isExecuting"];
    [NSThread detachNewThreadSelector:@selector(main) toTarget:self withObject:nil];
    executing = YES;
    [self didChangeValueForKey:@"isExecuting"];
}

- (void)main {
    @try {
        [self willChangeValueForKey:@"isExecuting"];
        executing = NO;
        [self didChangeValueForKey:@"isExecuting"];

        [self willChangeValueForKey:@"isFinished"];
        finished = YES;
        [self didChangeValueForKey:@"isFinished"];
    } @catch (NSException *exception) {
        NSLog(@"Exception: %@", exception);
    }
}

- (BOOL)isExecuting {
    return executing;
}

- (BOOL)isFinished {
    return finished;
}

- (BOOL)isConcurrent {
    return YES;
}

对于自定义oepration,start, isExecuting, isFinished, isConcurrent方法是必须实现的。main方法不是必须实现的,但是为了结构清晰,一般会把要做的任务放在main函数中。
start方法是operation的执行起点。但是当这个operation被cancel掉时,也需要设置operation的状态为finished。对于并发的operation,就是另外启动一个线程来执行main方法,同时isConcurrent方法一直返回YES。
另外我们得自己维护operation的状态,同时触发相应的KVO通知。

NSOperation VS GCD

NSOperation是对GCD的封装。使用NSOperation也就是在使用GCD。由于NSOperation是更高级的API,因此它拥有更多的功能。

  • 依赖性
  • 可观察状态
  • 停止,取消,启动
  • 控制并发

虽然苹果建议使用更高级的API,但是如果GCD能够满足要求的话,还是建议用GCD,因为它更轻量。如果需要按照一定顺序执行或者其他高要求的话,可以使用NSOpertation。

参考

Operation
Choosing Between NSOperation and Grand Central Dispatch
iOS 并发编程之 Operation Queues
iOS多线程之NSOperation和NSOperationQueue

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

推荐阅读更多精彩内容