Dispatch Group

Dispatch Queue中的多个任务处理全部结束后想要执行结束任务处理。

只使用一个Serial Dispatch Queue串行队列时,只需要把结束任务追加到最后即可。

当使用Concurrent Dispatch Queue并行队列或者多个Serial Dispatch Queue串行队列时,源代码就变得很复杂

在这种情况下就可以使用Dispatch Group

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_t group = dispatch_group_create();

dispatch_group_async(group, queue, ^{
NSLog(@"Task 1");
});
dispatch_group_async(group, queue, ^{
NSLog(@"Task 2");
});
dispatch_group_async(group, queue, ^{
NSLog(@"Task 3");
});

dispatch_group_notify(group, queue, ^{
NSLog(@"Task done.");
});
dispatch_group_async(group, queue, ^{
NSLog(@"Task 4");
});

控制台输出结果

1
2
3
4
5
Task 3
Task 4
Task 1
Task 2
Task done.

因为使用的是全局并发队列,所以执行任务的顺序不定,但此时的完成任务Task done.永远是最后执行。

使用dispatch_group_create来创建dispatch_group_t类型的Dispatch Group。

dispatch_group_async函数与dispatch_async相同,都是把任务追加到队列中,不同点在于多了一个Dispatch Group,并且任务属于Dispatch Group。Dispatch Group中并没有dispatch_group_sync函数。

追加到Dispatch Group中的任务全部执行结束后,使用dispatch_group_notify来通知所有的任务都已经执行结束。

dispatch_group_wait

1
2
3
4
long dispatch_group_wait(
dispatch_group_t group,
dispatch_time_t timeout
);

参数说明

参数 类型 描述
group dispatch_group_t 不能为空
timeout dispatch_time_t 提供DISPATCH_TIME_NOW和DISPATCH_TIME_FOREVER常量,等待多久。即超时时间

返回结果

long 类型, 返回0 则表示所有的任务都成功执行完毕。非0则表示正在执行,或者发生了错误。

马上执行

1
long result = dispatch_group_wait(group, DISPATCH_TIME_NOW);

永久等待

意思是只有所有的任务都执行完成后,才会等待才会结束。这个时候只会返回0。

1
long result = dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

自定义超时时间

超时时间一秒。

1
2
3
4
5
6
7
dispatch_time_t time = dispatch_time(DISPATCH_TIME_NOW, 1ull * NSEC_PER_SEC);
long result = dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
if (result == 0) {
NSLog(@"全部结束");
} else {
NSLog(@"正在执行");
}

另一种方式

之前使用的dispatch_group_asyncdispatch_group_notify,然后再更多的时候可能并没有queue队列。但是又想多个任务处理完成后执行完成任务。就可以使用dispatch_group_enterdispatch_group_leave,这是成对出现的。

dispatch_group_enter 执行该函数,异步执行的任务会被group监听.

dispatch_group_leave 任务执行完成.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"Task 1");
dispatch_group_leave(group);
});

dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"Task 2");
dispatch_group_leave(group);
});

dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"Task 3");
dispatch_group_leave(group);
});

dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"Task 4");
dispatch_group_leave(group);
});

long result = dispatch_group_wait(group, DISPATCH_TIME_FOREVER);

if (result == 0) {
NSLog(@"已经完成");
} else {
NSLog(@"正在执行");
}

控制台输出结果

1
2
3
4
5
Task 4
Task 3
Task 1
Task 2
已经完成

同时下载多张图片的时候,就可以使用这个方式,在最后通知主线程,去刷新界面。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
typedef void(^BatchPhotoDownloadingCompletionBlock)(NSError *error);

- (void)downloadPhotosWithCompletionBlock:(BatchPhotoDownloadingCompletionBlock)completionBlock {
__block NSError *error;
dispatch_group_t downloadGroup = dispatch_group_create();
for (NSUInteger index = 0; index < 5; index++) {
NSURL *URL = [NSURL URLWithString:[NSString stringWithFormat:@"http://lucaslz/%@", @(index)]];

dispatch_group_enter(downloadGroup);
[[NSURLSession sharedSession] dataTaskWithURL:URL completionHandler:^(NSData * _Nullable data, NSURLResponse * _Nullable response, NSError * _Nullable _error) {
if (_error) {
error = error;
}
// 处理图片

dispatch_group_leave(downloadGroup);
}];
}
dispatch_group_notify(downloadGroup, dispatch_get_main_queue(), ^{
if (completionBlock) {
completionBlock(error);
}
});
}

参考

grand-central-dispatch

坚持原创技术分享,您的支持将鼓励我继续创作!