例如有这样一个场景,有三个异步操作A,B,C, A与B相互不依赖,但是操作C需要等A和B都执行结束后才能执行
方法一: dispatch_group
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_queue_create("a", DISPATCH_QUEUE_CONCURRENT);
dispatch_group_async(group, queue, ^{
NSLog(@"block A start");
sleep(5);
NSLog(@"block A end");
});
dispatch_group_async(group, queue2, ^{
NSLog(@"block B start");
sleep(10);
NSLog(@"block B end");
});
dispatch_group_notify(group, queue3, ^{
NSLog(@"block C start");
});
原理:dispatch_group可以监测多个block对象,记录当前group中有多少个block对象在执行,并在当前group中的所有block对象都执行完之后执行一个特定的block。具体方法为 dispatch_group_async方法可以将block加入到指定的dispatch_group中(可以理解为数量上+1),当block执行结束时再将其移除,而dispatch_group_notify方法会在指定的group中所有的block都执行完之后再去执行相应的block
方法二: dispatch_barrier_async
dispatch_async(queue, ^{
NSLog(@"block A start");
sleep(5);
NSLog(@"block A end");
});
dispatch_async(queue, ^{
NSLog(@"block B start");
sleep(10);
NSLog(@"block B end");
});
dispatch_barrier_async(queue, ^{
NSLog(@"block C start");
});
原理:通过dispatch_barrier_async添加的block会在当前异步队列中在它之前添加的其他的block都执行完毕后才执行自己的block,在dispatch_barrier_async之后添加的block会等通过dispatch_barrier_async添加的block执行完毕之后才会执行
方法三:NSOperationQueue
NSOperationQueue *operationQueue = [[NSOperationQueue alloc] init];
NSOperation *operation1 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block A start");
sleep(5);
NSLog(@"block A end");
}];
NSOperation *operation2 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block B start");
sleep(10);
NSLog(@"block B end");
}];
NSOperation *operation3 = [NSBlockOperation blockOperationWithBlock:^{
NSLog(@"block C start");
}];
[operation3 addDependency:operation1];
[operation3 addDependency:operation2];
[operationQueue addOperation:operation1];
[operationQueue addOperation:operation2];
[operationQueue addOperation:operation3];
原理:NSOperationQueue支持添加dependency
方法四:dispatch_group_enter dispatch_group_leave
以上三种方法适用场景为我们能够控制异步返回block的情况,当我们对异步返回的block没有控制权时,比如有回调block的方法,上述方法就失效了,此时就需要用到 dispatch_group_enter dispatch_group_leave
比如有一个方法
- (void)handleSomethingForSeconds:(NSInteger)seconds withCompletion:(void (^)())completion
我们对completion没有直接控制权此时需要如下处理
dispatch_group_t group2 = dispatch_group_create();
dispatch_group_enter(group2);
[self handleSomethingForSeconds:5 withCompletion:^{
NSLog(@"complete A");
dispatch_group_leave(group2);
}];
dispatch_group_enter(group2);
[self handleSomethingForSeconds:10 withCompletion:^{
NSLog(@"complete B");
dispatch_group_leave(group2);
}];
dispatch_group_notify(group2, queue, ^{
NSLog(@"block C start");
});
原理:dispatch_group_enter会显示地给指定group中记录的正在执行的block数加一,dispatch_group_leave会显示地给指定group中记录的正在执行的block数减一,其他原理跟方法一相同,以此来实现等待的目的。