博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
队列组 iOS之多线程GCD(二)
阅读量:6207 次
发布时间:2019-06-21

本文共 10263 字,大约阅读时间需要 34 分钟。

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] 当前的线程为:
{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] 我就是任务三、来自线程:
{number = 5, name = (null)}2019-01-24 15:54:23.760459+0800 多线程demo[8498:280447] 我就是任务二、来自线程:
{number = 4, name = (null)}2019-01-24 15:54:23.760459+0800 多线程demo[8498:280444] 我就是任务一、来自线程:
{number = 3, name = (null)}2019-01-24 15:54:31.972052+0800 多线程demo[8498:280372] 我是要等任务-、任务二、任务三完成以后的最终任务、来自线程:
{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] 当前线程为:
{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] 我是任务一、来自线程
{number = 3, name = (null)}2019-01-24 16:55:43.773902+0800 多线程demo[9519:323890] 我是任务二、来自线程
{number = 4, name = (null)}2019-01-24 16:55:43.800804+0800 多线程demo[9519:323831] 我是任务三、来自线程
{number = 1, name = main}2019-01-24 16:55:44.776018+0800 多线程demo[9519:323889] 我是任务一、来自线程
{number = 3, name = (null)}2019-01-24 16:55:44.776010+0800 多线程demo[9519:323890] 我是任务二、来自线程
{number = 4, name = (null)}2019-01-24 16:55:44.802165+0800 多线程demo[9519:323831] 我是任务三、来自线程
{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] 当前线程为:
{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] 我是任务二、来自线程
{number = 3, name = (null)}2019-01-24 17:00:06.614622+0800 多线程demo[9608:327507] 我是任务一、来自线程
{number = 4, name = (null)}2019-01-24 17:00:07.620524+0800 多线程demo[9608:327506] 我是任务二、来自线程
{number = 3, name = (null)}2019-01-24 17:00:07.620543+0800 多线程demo[9608:327507] 我是任务一、来自线程
{number = 4, name = (null)}2019-01-24 17:00:08.620973+0800 多线程demo[9608:327439] 我是任务三、来自线程
{number = 1, name = main}2019-01-24 17:00:09.621951+0800 多线程demo[9608:327439] 我是任务三、来自线程
{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] 当前线程为:
{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] 我是任务三、来自线程:
{number = 4, name = (null)}2019-01-24 17:08:23.918048+0800 多线程demo[9777:334131] 我是任务一、来自线程:
{number = 3, name = (null)}2019-01-24 17:08:23.918050+0800 多线程demo[9777:334132] 我是任务二、来自线程:
{number = 5, name = (null)}2019-01-24 17:08:24.923557+0800 多线程demo[9777:334132] 我是任务二、来自线程:
{number = 5, name = (null)}2019-01-24 17:08:24.923557+0800 多线程demo[9777:334133] 我是任务三、来自线程:
{number = 4, name = (null)}2019-01-24 17:08:24.923557+0800 多线程demo[9777:334131] 我是任务一、来自线程:
{number = 3, name = (null)}复制代码

分析: NSLog(@"我一定要最后离开、因为我爱你");并没有最后离开。所有任务交错执行。

2.有dispatch_group_wait函数

2019-01-24 17:14:23.603205+0800 多线程demo[9928:339432] 当前线程为:
{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] 我是任务三、来自线程:
{number = 3, name = (null)}2019-01-24 17:14:24.605474+0800 多线程demo[9928:339495] 我是任务二、来自线程:
{number = 4, name = (null)}2019-01-24 17:14:24.605474+0800 多线程demo[9928:339493] 我是任务一、来自线程:
{number = 5, name = (null)}2019-01-24 17:14:25.606206+0800 多线程demo[9928:339495] 我是任务二、来自线程:
{number = 4, name = (null)}2019-01-24 17:14:25.606220+0800 多线程demo[9928:339503] 我是任务三、来自线程:
{number = 3, name = (null)}2019-01-24 17:14:25.606261+0800 多线程demo[9928:339493] 我是任务一、来自线程:
{number = 5, name = (null)}2019-01-24 17:14:25.606992+0800 多线程demo[9928:339432] 我一定要最后离开、因为我爱你复制代码

分析:确实最后离开了、dispatch_group_wait阻塞了当前线程、dispatch_group_wait后面的方法不能执行。

转载于:https://juejin.im/post/5c490d1b6fb9a04a0b2285f5

你可能感兴趣的文章
NYOJ-271 The 3n + 1 problem
查看>>
弃 Java 而使用 Kotlin 的你后悔了吗?| kotlin将会是最好的开发语言
查看>>
JavaScript 数据类型
查看>>
量子通信和大数据最有市场突破前景
查看>>
跟益达学Solr5之使用Tika从PDF中提取数据导入索引
查看>>
StringBuilder用法小结
查看>>
UVa 10252-Common Permutation
查看>>
Oracle RAC环境下如何更新patch(Rolling Patch)
查看>>
Delphi调用大漠插件示例
查看>>
BUAAOO第一单元的总结
查看>>
虚函数
查看>>
事件处理程序
查看>>
REST风格URL
查看>>
JS AngualrJs 指令
查看>>
解决-bash: fork: retry: Resource temporarily unavailable错误
查看>>
struct与 union的基本用法
查看>>
学习直接调用Webdriver JsonWireProtocol 的 RESTful API
查看>>
10.9的作业
查看>>
第 5 章 Nova - 040 - Migrate Instance 操作详解
查看>>
《正则表达式必知必会》读书笔记
查看>>