iOS锦囊

多线程-NSOperation

2018-02-06  本文已影响13人  mtry

概序

NSOperation

NSOperation作为一个在线程安全下管理状态变化、优先级、依赖性和取消等的抽象类,直接实例意义不大,一般使用是它的子类NSBlockOperation、 NSInvocationOperation 或继承(本文不考虑继承)

状态变化

一个NSOperation的开始可以通过调用start函数,如果添加到NSOperationQueue中则开始的时机是由队列决定的。NSOperation的状态变化isReady → isExecuting → isFinished,isReady如果是NO,那么任务现在处于等待当中,isExecuting(执行中)和isFinished(完成)则是互斥的

优先级

通过设置NSOperation的优先级(queuePriority)可以控制任务向线程派发的顺序

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
queue.suspended = YES;

for(NSInteger i = 0; i < 3; i++)
{
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"优先级低任务:%ld", i);
    }];
    operation.queuePriority = NSOperationQueuePriorityVeryLow;
    [queue addOperation:operation];
}

for(NSInteger i = 0; i < 3; i++)
{
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"优先级中任务:%ld", i);
    }];
    operation.queuePriority = NSOperationQueuePriorityNormal;
    [queue addOperation:operation];
}

for(NSInteger i = 0; i < 3; i++)
{
    NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
        NSLog(@"优先级高任务:%ld", i);
    }];
    operation.queuePriority = NSOperationQueuePriorityVeryHigh;
    [queue addOperation:operation];
}
 
queue.suspended = NO;

结果    
12:32:16.044 ObjectiveDemo[1215:69942] 优先级高任务:0
12:32:16.044 ObjectiveDemo[1215:69964] 优先级高任务:1
12:32:16.044 ObjectiveDemo[1215:69963] 优先级高任务:2
12:32:16.044 ObjectiveDemo[1215:70022] 优先级中任务:0
12:32:16.044 ObjectiveDemo[1215:69964] 优先级中任务:1
12:32:16.044 ObjectiveDemo[1215:69963] 优先级中任务:2
12:32:16.044 ObjectiveDemo[1215:69942] 优先级低任务:0
12:32:16.045 ObjectiveDemo[1215:70022] 优先级低任务:2
12:32:16.045 ObjectiveDemo[1215:69935] 优先级低任务:1

注意:只能控制队列中还没派发的任务顺序

依赖性

NSBlockOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"执行任务:1");
}];
NSBlockOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"执行任务:2");
}];
NSBlockOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"执行任务:3");
}];
NSBlockOperation *operation4 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"执行任务:4");
}];
NSBlockOperation *operation5 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"执行任务:5");
}];
NSBlockOperation *operation6 = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"执行任务:6");
}];
[operation1 addDependency:operation2];
[operation1 addDependency:operation3];
[operation1 addDependency:operation4];
[operation4 addDependency:operation5];
[operation4 addDependency:operation6];

NSOperationQueue *queue = [[NSOperationQueue alloc] init];
[queue addOperation:operation1];
[queue addOperation:operation2];
[queue addOperation:operation3];
[queue addOperation:operation4];
[queue addOperation:operation5];
[queue addOperation:operation6];

结果:4一定在5和6之后执行,1一定在2、3、4之后执行
14:10:11.133 ObjectiveDemo[1421:104016] 执行任务:5
14:10:11.133 ObjectiveDemo[1421:104022] 执行任务:3
14:10:11.133 ObjectiveDemo[1421:104024] 执行任务:2
14:10:11.133 ObjectiveDemo[1421:104010] 执行任务:6
14:10:11.134 ObjectiveDemo[1421:104010] 执行任务:4
14:10:11.134 ObjectiveDemo[1421:104016] 执行任务:1

注意:如果依赖关系出现环就会死锁

取消

相比GCD的取消NSOperation真是直接太多了。不过需要注意的是只能取消还没操作队列中还没执行的任务。

NSBlockOperation

能够并发地执行一个或多个block对象,所有相关的block都执行完之后,任务才算完成

NSBlockOperation *operation = [NSBlockOperation blockOperationWithBlock:^{
    NSLog(@"1");
}];
[operation addExecutionBlock:^{
    NSLog(@"2");
}];
[operation addExecutionBlock:^{
    NSLog(@"3");
}];
[operation setCompletionBlock:^{
    NSLog(@"done");
}];
[operation start];

结果
13:24:25.338 ObjectiveDemo[1317:86738] 1
13:24:25.338 ObjectiveDemo[1317:86790] 3
13:24:25.338 ObjectiveDemo[1317:86779] 2
13:24:25.340 ObjectiveDemo[1317:86779] done

NSInvocationOperation

基于一个target和SEL来创建操作,如果你已经有现有的方法来执行需要的任务,选它还是很方便的

- (nullable instancetype)initWithTarget:(id)target selector:(SEL)sel object:(nullable id)arg

当然如果需要传多个参数可以使用

- (instancetype)initWithInvocation:(NSInvocation *)inv
NSMethodSignature *methodSignature = [self methodSignatureForSelector:@selector(callBackArg1:arg2:)];
NSInvocation *invocation = [NSInvocation invocationWithMethodSignature:methodSignature];
invocation.target = self;
invocation.selector = @selector(callBackArg1:arg2:);
NSString *arg1 = @"111";
NSString *arg2 = @"222";

//设置参数的索引时不能从0开始,因为0已经被self占用,1已经被_cmd占用
[invocation setArgument:&arg1 atIndex:2];
[invocation setArgument:&arg2 atIndex:3];
NSInvocationOperation *operation = [[NSInvocationOperation alloc] initWithInvocation:invocation];

[operation setCompletionBlock:^{
    NSLog(@"done");
}];
[operation start];

- (void)callBackArg1:(id)arg1 arg2:(id)arg2
{
    NSLog(@"arg1 = %@ arg2 = %@", arg1, arg2);
}

NSOperationQueue

管理NSOperation的队列,控制任务的并发数和挂起等操作。并发数和挂起恢复操作只需简单的设置maxConcurrentOperationCount和suspended参数即可

注意

参考资料

NSOperation
多线程编程2 - NSOperation
多线程编程3 - NSOperationQueue

上一篇下一篇

猜你喜欢

热点阅读