dispatch_group_async、dispatch_group_notify
特点:当任务管理中的任务执行完会通知函数 dispatch_group_notify
我们经常遇到这样的面试题:异步下载几张图片、等待所有图片下载完成、合并一张大图、更新UI等等之类的需求。今天我们就用队列组解决这个问题。这里要用到dispatch_group_notify函数。
效果如下图所示:(为了便于理解、三张异步下载的小图也加载出来)
代码部分如下
//三张小图数组
NSMutableArray *array1;
//一张大图数组
NSMutableArray *array2;
//图片一二进制数据
NSData *data1;
//图片二二进制数据
NSData *data2;
//图片三二进制数据
NSData *data3;
- (void)groupNotify
{
NSLog(@"当前的线程为:%@",[NSThread currentThread]);
NSLog(@"开始");
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 追加任务1
for (int i = 0; i < 1; ++i) {
[NSThread sleepForTimeInterval:1];
NSLog(@"我就是任务一、来自线程:%@",[NSThread currentThread]);
NSURL *url = [NSURL URLWithString:@"http://imgsrc.baidu.com/imgad/pic/item/34fae6cd7b899e51fab3e9c048a7d933c8950d21.jpg"];
self->data1 = [NSData dataWithContentsOfURL:url];
UIImageView *imageView = self->array1[0];
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = [UIImage imageWithData:self->data1];
});
}
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 追加任务2
for (int i = 0; i < 1; ++i) {
[NSThread sleepForTimeInterval:1];
NSLog(@"我就是任务二、来自线程:%@",[NSThread currentThread]);
NSURL *url = [NSURL URLWithString:@"http://img17.3lian.com/d/file/201702/18/2b5f1b6298411b0045c5562da02fc6ac.jpg"];
self->data2 = [NSData dataWithContentsOfURL:url];
UIImageView *imageView = self->array1[1];
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = [UIImage imageWithData:self->data2];
});
}
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 追加任务3
for (int i = 0; i < 1; ++i) {
[NSThread sleepForTimeInterval:1];
NSLog(@"我就是任务三、来自线程:%@",[NSThread currentThread]);
NSURL *url = [NSURL URLWithString:@"http://img17.3lian.com/d/file/201702/23/dc458f76475470db9a5791848cb67801.jpg"];
self->data3 = [NSData dataWithContentsOfURL:url];
UIImageView *imageView = self->array1[2];
dispatch_async(dispatch_get_main_queue(), ^{
imageView.image = [UIImage imageWithData:self->data3];
});
}
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
// 所有图片下载完毕、合成一张图
for (int i = 0; i < 1; ++i) {
[NSThread sleepForTimeInterval:1];
UIImageView *imageView1 = self->array2[0];
UIImageView *imageView2 = self->array2[1];
UIImageView *imageView3 = self->array2[2];
imageView1.image = [UIImage imageWithData:self->data1];
imageView2.image = [UIImage imageWithData:self->data2];
imageView3.image = [UIImage imageWithData:self->data3];
NSLog(@"我是要等任务-、任务二、任务三完成以后的最终任务、来自线程:%@",[NSThread currentThread]);
}
NSLog(@"结束");
});
}
复制代码
打印结果:
2019-01-24 15:54:22.755688+0800 多线程demo[8498:280372] 当前的线程为:<NSThread: 0x60400006b9c0>{number = 1, name = main}
2019-01-24 15:54:22.755843+0800 多线程demo[8498:280372] 开始
2019-01-24 15:54:23.760460+0800 多线程demo[8498:280446] 我就是任务三、来自线程:<NSThread: 0x604000477640>{number = 5, name = (null)}
2019-01-24 15:54:23.760459+0800 多线程demo[8498:280447] 我就是任务二、来自线程:<NSThread: 0x604000477680>{number = 4, name = (null)}
2019-01-24 15:54:23.760459+0800 多线程demo[8498:280444] 我就是任务一、来自线程:<NSThread: 0x600000264b80>{number = 3, name = (null)}
2019-01-24 15:54:31.972052+0800 多线程demo[8498:280372] 我是要等任务-、任务二、任务三完成以后的最终任务、来自线程:<NSThread: 0x60400006b9c0>{number = 1, name = main}
2019-01-24 15:54:31.972156+0800 多线程demo[8498:280372] 结束
复制代码
分析:任务一、任务二、任务三采用异步下载(有各自的线程)、所以下载过程中是交错的而不是顺序执行,这也使得UI流畅,体验感好。所有任务完成时候、会走进dispatch_group_notify函数、在主线程更新UI,从而完成需求。
dispatch_group_enter、dispatch_group_leave
同样是类似上面的需求、当不用dispatch_group_async函数时、结合以上三个函数也能实现。
dispatch_group_enter、dispatch_group_leave成对出现、前者任务+1后者任务—1。当为0时才会追加到dispatch_group_notify函数中。
代码如下:(第一种注释dispatch_group_enter、dispatch_group_leave第二种打开注释)
NSLog(@"当前线程为:%@",[NSThread currentThread]); // 打印当前线程
NSLog(@"开始");
dispatch_group_t group = dispatch_group_create();
dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
// dispatch_group_enter(group);
dispatch_async(queue, ^{
// 追加任务1
for (int i = 0; i < 2; ++i) {
sleep(1);
NSLog(@"我是任务一、来自线程%@",[NSThread currentThread]);
}
// dispatch_group_leave(group);
});
// dispatch_group_enter(group);
dispatch_async(queue, ^{
// 追加任务2
for (int i = 0; i < 2; ++i) {
sleep(1);
NSLog(@"我是任务二、来自线程%@",[NSThread currentThread]);
}
// dispatch_group_leave(group);
});
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
for (int i = 0; i < 2; ++i) {
sleep(1);
NSLog(@"我是任务三、来自线程%@",[NSThread currentThread]);
}
NSLog(@"结束");
});
复制代码
打印结果一:(注释dispatch_group_enter、dispatch_group_leave)
2019-01-24 16:55:42.769970+0800 多线程demo[9519:323831] 当前线程为:<NSThread: 0x604000071100>{number = 1, name = main}
2019-01-24 16:55:42.770108+0800 多线程demo[9519:323831] 开始
2019-01-24 16:55:43.773884+0800 多线程demo[9519:323889] 我是任务一、来自线程<NSThread: 0x60400047a000>{number = 3, name = (null)}
2019-01-24 16:55:43.773902+0800 多线程demo[9519:323890] 我是任务二、来自线程<NSThread: 0x600000276d40>{number = 4, name = (null)}
2019-01-24 16:55:43.800804+0800 多线程demo[9519:323831] 我是任务三、来自线程<NSThread: 0x604000071100>{number = 1, name = main}
2019-01-24 16:55:44.776018+0800 多线程demo[9519:323889] 我是任务一、来自线程<NSThread: 0x60400047a000>{number = 3, name = (null)}
2019-01-24 16:55:44.776010+0800 多线程demo[9519:323890] 我是任务二、来自线程<NSThread: 0x600000276d40>{number = 4, name = (null)}
2019-01-24 16:55:44.802165+0800 多线程demo[9519:323831] 我是任务三、来自线程<NSThread: 0x604000071100>{number = 1, name = main}
2019-01-24 16:55:44.802362+0800 多线程demo[9519:323831] 结束
复制代码
分析结果:没有dispatch_group_enter、dispatch_group_leave函数、三个任务交错执行、互不影响。
打印结果二:(打开注释)
2019-01-24 17:00:05.609413+0800 多线程demo[9608:327439] 当前线程为:<NSThread: 0x604000068ac0>{number = 1, name = main}
2019-01-24 17:00:05.609562+0800 多线程demo[9608:327439] 开始
2019-01-24 17:00:06.614555+0800 多线程demo[9608:327506] 我是任务二、来自线程<NSThread: 0x60400046de00>{number = 3, name = (null)}
2019-01-24 17:00:06.614622+0800 多线程demo[9608:327507] 我是任务一、来自线程<NSThread: 0x60400027f4c0>{number = 4, name = (null)}
2019-01-24 17:00:07.620524+0800 多线程demo[9608:327506] 我是任务二、来自线程<NSThread: 0x60400046de00>{number = 3, name = (null)}
2019-01-24 17:00:07.620543+0800 多线程demo[9608:327507] 我是任务一、来自线程<NSThread: 0x60400027f4c0>{number = 4, name = (null)}
2019-01-24 17:00:08.620973+0800 多线程demo[9608:327439] 我是任务三、来自线程<NSThread: 0x604000068ac0>{number = 1, name = main}
2019-01-24 17:00:09.621951+0800 多线程demo[9608:327439] 我是任务三、来自线程<NSThread: 0x604000068ac0>{number = 1, name = main}
2019-01-24 17:00:09.622129+0800 多线程demo[9608:327439] 结束
复制代码
分析结果:任务三始终在任务一、二结束完毕执行。任务一、任务二交错执行。
dispatch_group_wait
特点:group中的任务完成之后 才能执行下面的函数。 代码如下:
NSLog(@"当前线程为:%@",[NSThread currentThread]); // 打印当前线程
NSLog(@"开始");
dispatch_group_t group = dispatch_group_create();
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 任务1
for (int i = 0; i < 2; i ++) {
sleep(1);
NSLog(@"我是任务一、来自线程:%@",[NSThread currentThread]);
}
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 任务2
for (int i = 0; i < 2; i ++) {
sleep(1);
NSLog(@"我是任务二、来自线程:%@",[NSThread currentThread]);
}
});
dispatch_group_async(group, dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
// 任务3
for (int i = 0; i < 2; i ++) {
sleep(1);
NSLog(@"我是任务三、来自线程:%@",[NSThread currentThread]);
}
});
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"我一定要最后离开、因为我爱你");
复制代码
打印结果:
1.没dispatch_group_wait函数
2019-01-24 17:08:22.912309+0800 多线程demo[9777:334058] 当前线程为:<NSThread: 0x600000261500>{number = 1, name = main}
2019-01-24 17:08:22.912460+0800 多线程demo[9777:334058] 开始
2019-01-24 17:08:22.912600+0800 多线程demo[9777:334058] 我一定要最后离开、因为我爱你
2019-01-24 17:08:23.918052+0800 多线程demo[9777:334133] 我是任务三、来自线程:<NSThread: 0x6000004697c0>{number = 4, name = (null)}
2019-01-24 17:08:23.918048+0800 多线程demo[9777:334131] 我是任务一、来自线程:<NSThread: 0x60000046efc0>{number = 3, name = (null)}
2019-01-24 17:08:23.918050+0800 多线程demo[9777:334132] 我是任务二、来自线程:<NSThread: 0x604000660800>{number = 5, name = (null)}
2019-01-24 17:08:24.923557+0800 多线程demo[9777:334132] 我是任务二、来自线程:<NSThread: 0x604000660800>{number = 5, name = (null)}
2019-01-24 17:08:24.923557+0800 多线程demo[9777:334133] 我是任务三、来自线程:<NSThread: 0x6000004697c0>{number = 4, name = (null)}
2019-01-24 17:08:24.923557+0800 多线程demo[9777:334131] 我是任务一、来自线程:<NSThread: 0x60000046efc0>{number = 3, name = (null)}
复制代码
分析: NSLog(@"我一定要最后离开、因为我爱你");并没有最后离开。所有任务交错执行。
2.有dispatch_group_wait函数
2019-01-24 17:14:23.603205+0800 多线程demo[9928:339432] 当前线程为:<NSThread: 0x60400006c280>{number = 1, name = main}
2019-01-24 17:14:23.603338+0800 多线程demo[9928:339432] 开始
2019-01-24 17:14:24.605474+0800 多线程demo[9928:339503] 我是任务三、来自线程:<NSThread: 0x600000467bc0>{number = 3, name = (null)}
2019-01-24 17:14:24.605474+0800 多线程demo[9928:339495] 我是任务二、来自线程:<NSThread: 0x6040002781c0>{number = 4, name = (null)}
2019-01-24 17:14:24.605474+0800 多线程demo[9928:339493] 我是任务一、来自线程:<NSThread: 0x600000467b00>{number = 5, name = (null)}
2019-01-24 17:14:25.606206+0800 多线程demo[9928:339495] 我是任务二、来自线程:<NSThread: 0x6040002781c0>{number = 4, name = (null)}
2019-01-24 17:14:25.606220+0800 多线程demo[9928:339503] 我是任务三、来自线程:<NSThread: 0x600000467bc0>{number = 3, name = (null)}
2019-01-24 17:14:25.606261+0800 多线程demo[9928:339493] 我是任务一、来自线程:<NSThread: 0x600000467b00>{number = 5, name = (null)}
2019-01-24 17:14:25.606992+0800 多线程demo[9928:339432] 我一定要最后离开、因为我爱你
复制代码
分析:确实最后离开了、dispatch_group_wait阻塞了当前线程、dispatch_group_wait后面的方法不能执行。