您好!欢迎来到爱源码

爱源码

热门搜索: 抖音快手短视频下载   

iOS多线程的详细解释(实现章节-GCD) 《电影网站源码》

  • 时间:2022-08-10 01:09 编辑: 来源: 阅读:280
  • 扫一扫,手机访问
摘要:iOS多线程的详细解释(实现章节-GCD) 《电影网站源码》
多线程-GCD.png上一节我们学习了Apple-NSThread提供的实现多线程的面向对象方法。 在这一节中,我们学习如何在C语言GCD中实现多线程,这也是我们项目中经常使用的一种方法。 Nthread链接:详细解释多线程(实现章节-Nthread)。概念章节链接:详细讲解多线程(概念章节——进程、线程和多线程原理)。源代码链接:weiman152/Multithreading.git .多线程的实现方法1 .硝酸铈铵。GCD(C语言)3。n操作(OC) 4。pthread(C语言)5。实现多线程的其他方法。本章主要内容提醒:GCD概念重要概念:任务(同步、异步)重要概念:队列(串行、并发)GCD用例:图片下载栅栏函数延迟一次性代码8_1的执行。一次性代码案例:单实例快速迭代队列组10_1。队列组案例(图片下载后合成)1。GCD概念GCD的整个流程就是大中央调度,简单翻译就是大中央调度。 也是苹果开发的多线程处理方式。 GCD是C语言中的一种多线程处理方法,充分利用了CPU的多核并行操作。 在GCD中,有两个重要的概念:任务和队列。 当我们使用GCD时,我们都在处理这两个概念。如果这两个概念不清楚,我们在使用的时候就会很困惑。 让我们一起来学习这两个重要的概念。 2.重要概念:任务(同步,异步)什么是任务?我们上学的时候,老师说,给你布置一个作业。今天我负责收全班的作业。 收作业。这项行动是一项任务。 那么,任务是什么?是要执行的操作。 很好理解吧?什么是同步(sync)?不要启动新线程,将任务添加到当前线程,并等待任务完成。 什么是异步?您可以启动一个新线程,并且可以将任务添加到新线程中。您可以继续执行,而不必等待队列完成。 例如,如果你想做午餐的任务 同步就是你只有一个锅一个灶,只能先把饭煮好,再煮。 异步执行就是你有两个锅,两个灶,一个煮饭,一个做饭。 注意:虽然异步执行有能力启动一个新线程,但不确定会启动一个新线程。 3.重要概念:队列(串行、并发)什么是调度队列?排队也很好理解。 我们都见过排队,排队买食物,排队买票,排队等公共汽车,等等。 排队的时候,队列最前面的总是最先进入,后面的最后进入,这就是FIFO。 队列的含义如下:队列的含义是队列中的队列。pngGCD,它管理多个线程。 在队列中,有两个概念,串行队列和并发队列。 什么是串行队列?我们都吃过冰糖葫芦,一个一个,也吃过烤串,一个一个,总是先吃上面的,一个一个吃下面的。 串行队列类似,一个任务完成,然后进行下一个任务。 串行queue.png什么是并发队列?您可以打开多个线程以允许任务并发执行。 但是,并发队列仅在任务异步时有效。 Concurrency+Asynchronous.png理解了这些概念,我们就开始用GCD创建多线程吧。 4.GCD的使用。使用GCD的步骤:1。创建队列(串行和并发);2)自定义任务(同步和异步)(想做什么);3 "将任务添加到队列中以供执行。 GCD会自动取出队列中的任务,放到相应的线程中执行。 任务提取标准或先进先出 创建队列//1。创建队列/* */第一个参数const char *label: C语言字符串,用于标识//第二个参数DISPATCH _ QUEUE _ attr _ t attr _ TT attr:队列的类型//并发队列:DISPATCH_QUEUE_CONCURRENT//串行队列:DISPATCH_QUEUE_SERIAL或null DISPATCH _ QUEUE _ t QUEUE = DISPATCH _ QUEUE _ create(const char * label,DISPATCH _ QUEUE _ attr _ t attr);*///Queue -(void)test{ //1.1并发队列//可以启动多个线程,并发执行任务dispatch _ Queue _ TBF Queue = dispatch _ Queue _ create(" BF Queue ",dispatch _ Queue _ Concurrent);//1.2串行队列//任务相继执行,一个线程中dispatch _ queue _ t CX queue = dispatch _ queue _ create(" CX queue ",dispatch _ queue _ serial);//1.3系统默认提供全局并发队列使用。/* *系统默认全局队列dispatch _ get _ global _ queue(dispatch _ queue _ priority _ default,0);第一个参数:队列优先级# defined disptch _ QUEUE _ PRIORITY _ high 2//high # defined disptch _ QUEUE _ PRIORITY _ DEFAULT 0//DEFAULT # defined disptch _ QUEUE _ PRIORITY _ low(-2)//low # defined disptch _ QUEUE _ PRIORITY _ background int 16 _ min//后端第二个参数:预留参数0 */DISPATCH _ QUEUE _ t global q = DISPATCH _ get _ global _ QUEUE(DISPATCH _ QUEUE _ PRIORITY _ DEFAULT,0);//1.4获取主队列dispatch _ queue _ TMA inq = dispatch _ Get _ main _ queue();}创建任务//task -(void)test2{ //1。同步任务:立即开始执行。/* *第一个参数:队列第二个参数:要执行的操作,是一个block */dispatch _ sync(dispatch _ get _ main _ queue(),{//同步执行任务}) //2。异步任务:主线程执行完毕后,启动子线程执行任务dispatch _ async(dispatch _ get _ global _ queue(0,0),{//异步任务});}任务和队列的组合让我们排列和组合任意一个and队列,看看各自的结果。 1.同步任务+串行队列2。同步任务+并发队列3。异步任务+串行队列4。异步任务+并发队列5。同步任务+主队列6。异步任务+主队列7。同步任务+全局队列8。异步任务+全局队列1。同步任务+串行队列//1。同步任务+串行队列-(I action)GCC/* *总结:同步任务是在不打开新线程的情况下,将任务添加到当前线程中。当前线程是主线程,所以将其添加到主线程中。串行队列是一个接一个地执行任务。 这里有三个任务,即第一个任务、第二个任务和第三个任务。 打印结果:2020-09-29 15:03:58.965539+0800多线程[3069:121374]开始测试!020-09-29 15: 03: 58.965869+0800多线程[3069:121374] 1。同步任务+串行队列2020-09-29 15:03:58.966169+0800多线程[3069:12133 NSThread:0x 600000478980 >{number = 1,name = main } 2020-09-29 15:04:00.967371+0800多线程[3069:121374]同步任务二+串行,休眠2秒2020-09-29 15:04:00.96774 NSThread:0x 600000478980 & gt;{number = 1,name = main } 2020-09-29 15:04:00.967987+0800多线程[3069:121374]同步任务III+Serial 2020-09-29 15:04:00.968206+0800多线程NSThread:0x 600000478980 & gt;{number = 1,name = main } 2020-09-29 15:04:00.968428+0800多线程[3069:121374]测试结束!*///我们自己创建一个线程试试吧[nsthread detachnewthreadwithblock:{[self test 1 _ 1];}];//结果和上次一样。/* * 2020-09-29 15:30:53.381501+0800多线程[3253:131992]开始测试!020-09-29 15: 30: 53.381831+0800多线程[3253:131992] 1。同步任务+串行队列2020-09-29 15:30:53.382813+0800多线程[3253:13199 NSThread:0x 600003 f 53680 & gt;{number = 7,name =(null)} 2020-09-29 15:30:55.386012+0800多线程[3253:131992]同步任务二+串行,休眠2秒2020-09-29 15:30:55.3866 . 300000000005 NSThread:0x 600003 f 53680 & gt;{number = 7,name =(null)} 2020-09-29 15:30:55.386772+0800多线程[3253:131992]同步任务III+Serial 2020-09-29 15:30:55.387163+00 NSThread:0x 600003 f 53680 & gt;{number = 7,name =(null)} 2020-09-29 15:30:55.387616+0800多线程[3253:131992]测试结束!*/}-(void)test1_1{ NSLog(@“我们开始测试吧!”);//1.同步任务+串行队列DISPATCH _ QUEUE _ tcx Q1 = DISPATCH _ QUEUE _ create("串行队列一",DISPATCH _ QUEUE _ SERIAL);Dispatch _ sync (cxq1,{nslog (@ "1。同步任务+串行队列”);NSLog(@“当前线程:%@”,[NSThread current thread]);});dispatch_sync(cxQ1,^{[nsthread sleepfortimeinterval:2.0];NSLog(@“同步任务2+串口,睡了2秒”);NSLog(@“当前线程:%@”,[NSThread current thread]);});Dispatch _ sync (cxq1,{nslog (@“同步任务3+串行”);NSLog(@“当前线程:%@”,[NSThread current thread]);});NSLog(@“测试结束了!”);}含义:同步任务+串行队列. png2 .同步任务+并发队列//2。同步任务+并发队列-(I action)gcd test 2:(id)发送方{nslog (@ "开始测试,2。同步任务+并发队列”);DISPATCH _ QUEUE _ tbfq = DISPATCH _ QUEUE _ create("并发队列",DISPATCH _ QUEUE _ CONCURRENT);Dispatch _ sync (bfq,{nslog (@“任务一”);NSLog(@“当前线程:%@”,[NSThread current thread]);});dispatch _ sync(^{ bfq[nsthread sleepfortimeinterval:3.0];NSLog(@“任务2”);NSLog(@“当前线程:%@”,[NSThread current thread]);});Dispatch _ sync (BFQ,{nslog (@“任务3”));NSLog(@“当前线程:%@”,[NSThread current thread]);});NSLog(@“测试结束”);/* *总结:同步任务并添加到当前线程,当前线程在主线程中,所以三个任务都添加到主线程中执行。 */}打印结果:image.png总结:同步任务,将任务添加到当前线程,当前线程在主线程中,所以三个任务都添加到主线程中执行。 同步任务没有启动新线程的能力,因此没有新线程。 意思如下:image.png3异步任务+串行队列//3。异步任务+串行队列-(I action)gcd test 3:(id)发送方{nslog (@ "开始测试,3。异步任务+串行队列”);DISPATCH _ QUEUE _ t cxq = DISPATCH _ QUEUE _ create(",DISPATCH _ QUEUE _ SERIAL);Dispatch _ async (cxq,{ nslog(@ " task one "));NSLog(@“当前线程:%@”,[NSThread current thread]);});dispatch_async(cxq,^{[nsthread sleepfortimeinterval:2.0];NSLog(@“任务2”);NSLog(@“当前线程:%@”,[NSThread current thread]);});Dispatch _ async (cxq,{ nslog(@ " Task 3 "));NSLog(@“当前线程:%@”,[NSThread current thread]);});NSLog(@“测试结束了!”);}打印结果:image.png的总结:异步任务可以在不阻塞当前线程的情况下打开新线程。 它是当前的主线程。由于开始一个新线程需要时间,所以先打印主线程的两个句子。 线程启动后,因为是串行队列,任务在队列中一个一个执行。 意思如下:image.png4异步任务+并发队列//4。异步任务+并发队列-(I action)gcd test 4:(id)发送方{nslog (@“测试开始,异步任务+并发队列”);DISPATCH _ QUEUE _ tbfq = DISPATCH _ QUEUE _ create("并发队列",DISPATCH _ QUEUE _ CONCURRENT);Dispatch _ async (BFQ,{nslog (@“任务一”));NSLog(@"1。当前线程:%@ ",[NSThread current thread]);});dispatch _ async(^{ bfq[nsthread sleepfortimeinterval:2.0];NSLog(@“任务2”);NSLog(@"2。当前线程:%@ ",[NSThread current thread]);});Dispatch _ async (BFQ,{ nslog(@ " Task 3 "));NSLog(@"3。当前线程:%@ ",[NSThread current thread]);});NSLog(@“测试结束了!”);}打印结果:image.png总结:异步任务具有启动新线程的能力。在这种情况下,有三个任务启动了三个线程。 并发队列将任务分配给子线程执行。 意图如下:image.png5同步任务+主队列(死锁)//5。同步任务+主队列:deadlock-(I action)gcd test 5:(id)sender { nslog(@“测试开始,同步任务+主队列”);dispatch _ sync(dispatch _ get _ main _ queue(),{nslog (@“任务一”));NSLog(@"1。线程:%@ ",[NSThread current thread]);});NSLog(@“测试结束”);}结果:为什么是deadlock.png?下面我们按照任务来详细划分一下代码:image.png很多人会把上面的代码分成三个任务,但是我觉得分成四个任务更能理解死锁是怎么产生的,因为就算任务四不存在,死锁还是会发生。 个人分析:目前在主线程中,任务一执行成功,就执行dispatch_sync函数,这是第二个任务,函数体是执行第三个任务。 在第三个任务完成之前,第二个任务不能返回。 因为主线程是串行的,所以任务3在任务2之后执行。 这导致任务2在执行后等待任务3返回,任务3在执行前等待任务2返回。 两人僵持不下,互相等待,导致僵局。 意思如下:image.png6异步任务+主队列//6。异步任务+主队列-(I action)gcd test 6:(id)发送方{nslog (@“测试开始,异步任务+主队列”);dispatch _ async(dispatch _ get _ main _ queue(),{nslog (@“任务一”));NSLog(@"1。线程:%@ ",[NSThread current thread]);});dispatch _ async(dispatch _ get _ main _ queue(),^{[nsthread sleepfortimeinterval:2.0];NSLog(@“任务2”);NSLog(@"2。线程:%@ ",[NSThread current thread]);});dispatch _ async(dispatch _ get _ main _ queue(),{nslog (@“任务三”));NSLog(@"3。线程:%@ ",[NSThread current thread]);});NSLog(@)测试结束 ");}打印结果:image.png总结:我们知道主队列是一个串行队列,异步任务可以启动新线程,但是不确定要启动新线程。 不是启动一个新线程,而是将任务添加到主线程中。 异步任务不会阻塞主线程,所以先打印主线程中的两个句子,然后依次执行三个任务。 意图如下:image.png7同步任务+全局队列(也是并发队列)//7。同步任务+全局队列(也是并发队列)-(I action)gcd test 7:(id)发送方{nslog (@“开始,同步任务+全局队列(也是并发队列)”);dispatch _ queue _ t global = dispatch _ get _ global _ queue(0,0);Dispatch _ sync (global,{ nslog(@ " task one "));NSLog(@"1。线程:%@ ",[NSThread current thread]);});dispatch_sync(全球,^{[nsthread sleepfortimeinterval:2.0];NSLog(@“任务2”);NSLog(@"2。线程:%@ ",[NSThread current thread]);});Dispatch _ sync (global,{ nslog(@ " Task 3));NSLog(@"3。线程:%@ ",[NSThread current thread]);});NSLog(@“测试结束了!”);}结果:image.png的总结:同步任务不是启动一个新线程,而是将任务添加到当前线程,也就是主线程。 全局队列是并发队列,并发队列只有在任务异步时才能工作。因为目前只有一个线程,所以并发没有影响。 因为同步任务将阻塞当前线程,直到任务完成。 因此,首先打印主线程中的第一行代码,然后阻塞并执行同步任务,即任务1、任务2和任务3,直到所有任务完成,打印主线程的最后一行。 意图如下:image.png8异步任务+全局队列(也是并发队列)//8。异步任务+全局队列(也称并发队列)-(I action)gcd test 8:(id)发送方{nslog (@ "start,异步任务+全局队列");dispatch _ queue _ t global = dispatch _ get _ global _ queue(0,0);Dispatch _ async (global,{ nslog(@ " task one "));NSLog(@"1。线程:%@ ",[NSThread current thread]);});dispatch_async(全局,^{[nsthread sleepfortimeinterval:2.0];NSLog(@“任务2”);NSLog(@"2。线程:%@ ",[NSThread current thread]);});Dispatch _ async (global,{ nslog(@ " Task 3));NSLog(@"3。线程:%@ ",[NSThread current thread]);});NSLog(@“测试结束”);}打印结果:image.png总结:异步任务可以打开新线程。 这里的三个异步任务打开了三个线程。 全局队列也是一个并发队列,它将任务分配给三个子线程执行。 主线程不会阻塞,所以直接打印主线程的内容。 启动子线程需要时间。 因为任务2睡了2秒,所以先打印任务1和任务3,最后打印任务2。 意图如下:image.pngGCDGCDGCD的任务和队列汇总:image.png更简单:image.png经过观察发现,同步任务会阻塞当前线程,而不会打开新线程,且多为串行执行任务。 异步任务不会阻塞当前线程,大部分会打开新线程。 5.案例:下载图片。因为下载图片是一个比较耗时的操作,所以我们一般都是在子线程中下载,下载完之后再放到主线程中进行显示。 让我们用GCD来演示这个过程。 //案例:下载图片并显示-(IB Action)下载:(ID)发件人{ ns string * URL = @ " https://Tim GSA . Baidu . com/timg?图像与图像。质量= 80 & ampsize = b9999 _ 10000 & ampsec=1601469152745。di = b 68 e 17d 74 c 30d 400 E1 df 9473 ded 0 eb1c & amp;imgtype = 0 & ampsrc = http % 3A % 2F % 2 FH bimg . huabanimg . com % 2 f 959 c 8754d 77244788 F5 A8 f 775 ee 36 de C4 a5d 362 e 236d 9-EP 3 ci 9 _ fw 658 ";dispatch _ queue _ t global = dispatch _ get _ global _ queue(0,0);dispatch_async(global,^{ nsurl * imgurl =[nsurl URL with string:URL];ns data * data =[ns data datawithcontentsourl:imgUrl];ui image * image =[ui image imageWithData:data];NSLog(@ "下载图形的线程:%@ ",[NSThread current thread]);//回到主线程,赋值dispatch _ async(dispatch _ get _ main _ queue(),{ self . show img . image = image;NSLog(@ "显示图形的线程:%@ ",[NSThread current thread]);});});}结果:待下载。下载后的png。png打印结果:image.png6 Fence函数dispatch _ barrier _ async (queue,{ nslog(@ " # # # # # # # # # # # # # #我是Fence # # # # # # # # # # #);栅栏函数用于控制任务的执行顺序。我们用代码试一下。我们使用异步任务+并发队列。 //fence函数——(I action)zhalan:(id)sender {//fence函数,可以控制任务的执行顺序。//1.创建并发队列DISPATCH _ QUEUE _ t QUEUE = DISPATCH _ QUEUE _ create(" CONCURRENT QUEUE ",DISPATCH _ QUEUE _ CONCURRENT);//2.Create task,async task dispatch _ async(queue,{ nslog(@“task one”));[自运行:@ " 1 "];});Dispatch _ async (queue,{ nslog(@ " Task 2));[自跑:@ " 2 "];});Dispatch _ async (queue,{nslog (@“任务三”));【自跑:@ " 3 "】;});Dispatch _ async (queue,{nslog (@“任务四”));【自跑:@ " 4 "】;});}-(void)run:(ns string *)mark { for(int I = 0;我& lt5;++) {nslog (@ "任务:% @,i = %d,线程:% @ ",mark,I,[nsthread当前线程]);}}}打印结果:image.png线程并发执行,任务顺序不可控。 使用栅栏功能后再来看看。 //fence函数——(I action)zhalan:(id)sender {//fence函数,可以控制任务的执行顺序。//1.创建并发队列DISPATCH _ QUEUE _ t QUEUE = DISPATCH _ QUEUE _ create(" CONCURRENT QUEUE ",DISPATCH _ QUEUE _ CONCURRENT);//2.Create task,async task dispatch _ async(queue,{ nslog(@“task one”));[自运行:@ " 1 "];});Dispatch _ async (queue,{ nslog(@ " Task 2));[自跑:@ " 2 "];});//栅栏函数dispatch _ barrier _ async (queue,{ nslog(@ " # # # # # # # # # # # # #我是栅栏# # # # # # # # # # ";});Dispatch _ async (queue,{nslog (@“任务三”));【自跑:@ " 3 "】;});Dispatch _ async (queue,{nslog (@“任务四”));【自跑:@ " 4 "】;});}-(void)run:(ns string *)mark { for(int I = 0;我& lt5;++) {nslog (@ "任务:% @,i = %d,线程:% @ ",mark,I,[nsthread当前线程]);}}image.pngimage.png我们发现使用栅栏函数后,栅栏前面的前两个任务都完成了,然后执行栅栏函数,最后执行后面的任务。 就像栅栏一样,把异步的乱序任务隔离开来,变成偏序的代码。 7.延期执行有时候,我们需要将一些操作延期几秒钟。这时候我们可以用GCD的dispatch_after来实现。 Dispatch_after不阻塞当前线程,可以在主线程或子线程中执行代码。 //延期执行-(I action)Yanchi:(id)sender {//在主线程中延期执行NSLog(@ 2秒(@“开始!”);dispatch _ after(dispatch _ time(dispatch _ time _ now,(int64 _ t) (2.0 * nsec _ per _ sec)),dispatch _ get _ main _ queue(),{nslog (@ "哈哈哈哈,延迟");NSLog(@“当前线程:%@”,[NSThread current thread]);});NSLog(@“完了”);//延迟NSLog的执行(@在子线程中3秒(@“重新开始”);dispatch _ after(dispatch _ time(dispatch _ time _ now,(int64 _ t) (3.0 * nsec _ per _ sec))、dispatch _ get _ global _ queue (0,0)、{nslog (@“哎呀,3秒”)nslog (@“当前线程:%@”、[NSThread current thread]);});NSLog(@“又完了!”);}结果:image.png延迟执行,我们还有其他方法,比如://延迟执行的其余方法[self perform selector:@ selector(YC)with object:nil after delay:2.0];[NSTimer scheduledTimerWithTimeInterval:2.0目标:自身选择器:@选择器(YC) userInfo:nil重复次数:否];-(void)YC {NSLog(@ "延迟执行,线程:%@ ",[NSThread current thread]);}结果:image.png也可以延期。 但是,这两种方法都在主线程中执行。 8.一次性代码dispatch_once我们在创建单例时经常使用GCD的dispatch_once方法,以保证代码只会执行一次。 静态dispatch _ once _ t onceTokendispatch _ once(amp;Once token,{nslog (@ "这段代码只执行一次。 ");});因为这段代码经常在单例中使用,所以让我们创建一个单例来试试。 8_1.一次性代码案例:单个image.png代码如下:gcd test . h///gcd test . h//多线程///由温华暖于2020/10/2创建。//版权所有2020 weiman .保留所有权利。//# import < Foundation/Foundation . h & gt;NS _ ASSUME _ NONNULL _ BEGIN @ interface gcd test:NS object & lt;NSCopying,NSMutableCopying & gt+(instance type)shareGCDTest;@ endNS _ ASSUME _ NONNULL _ endgcdtest . m////gcdtest . m//多线程////文欢欢2020/10/2创建。//版权所有2020威曼。保留所有权利。//# import " gcd test . h " @ implementation gcd test+(instance type)shareGCDTest { return[[self alloc]init];}静态GCDTest *实例;+(instance type)allocWithZone:(struct _ ns zone *)zone { static dispatch _ once _ t once token;dispatch _ once(amp;onceToken,^{ if(instance = = nil){ instance =[super allocwithszone:zone];} });返回实例;}-(id)copy with zone:(ns zone *)zone { return instance;}-(id)mutablecopywithszone:(ns zone *)zone { return instance;} @ end test://一次性代码-(I action)once action:(id)发送方{ static dispatch _ once _ tconce token;dispatch _ once(amp;Once token,{nslog (@ "这段代码只执行一次。 ");});//创建单个实例并尝试gcd test * test1 =[[gcd test alloc]init];gcd test * test 2 =[gcd test shareGCDTest];GCDTest * test3 = [test1副本];gcd test * test 4 =[test1 mutable copy];NSLog(@"test1:%@ ",test1);NSLog(@"test2:%@ ",test2);NSLog(@"test3:%@ ",test3);NSLog(@"test4:%@ ",test4);}看看结果:image.png,我们发现我们创建的四个对象的地址都是一样的,这是一个合法的单例。 9.快速迭代当我们需要使用循环时,我们通常使用for循环、for_in循环、while循环、do循环...while循环,swift中还有很多其他循环。 在GCD中,我们还提供了一个快速循环方法dispatch_apply。 /*第一个参数:迭代次数;第二个参数:执行哪个队列;第三个参数:block */dispatch _ apply (10,queue,(size _ t index) {})要执行的任务;为什么是快速迭代?因为它将打开多个线程并同时执行循环中的操作 如果在串行队列中,dispatch_apply按照与for循环相同的顺序执行,则没有意义。 在并发队列中,dispatch_apply会打开多个线程进行并发执行,从而提高效率。 //快速迭代-(I action)kuaisu:(id)sender { nslog(@ "开始快速迭代");dispatch _ queue _ t queue = dispatch _ get _ global _ queue(0,0);Dispatch _ apply (10,queue,(size _ t index) {nslog (@ "index =% zd,thread:% @ ",index,[nsthread current thread]);});}结果:image.png10队列组队列组在组内所有并发线程执行完毕后,可以执行一些操作。 //创建队列组dispatch _ group _ t group = dispatch _ group _ Create();//创建并行队列dispatch _ queue _ t queue = dispatch _ get _ global _ queue(0,0);//执行队列组任务dispatch _ group _ async (group,queue,{ });//队列组中的任务完成后,执行函数dispatch _ group _ notify (group,queue,{ });看一个简单的例子://queue group-(I action)duilie:(id)sender {//Create queue group dispatch _ group _ t group = dispatch _ group _ Create();//创建并发队列DISPATCH _ QUEUE _ t QUEUE = DISPATCH _ QUEUE _ Create(" CONCURRENT ",DISPATCH _ QUEUE _ CONCURRENT);//执行队列组任务dispatch _ group _ async (group,queue,{nslog (@“这是一个队列组中的任务,编号1”);NSLog(@“任务一:线程%@”,[NSThread current thread]);});dispatch_group_async(组,队列,^{[nsthread sleepfortimeinterval:1.0];NSLog(@“这是一个队列组中的任务,编号2,休眠1秒”);NSLog(@“任务2:线程%@”,[NSThread current thread]);});dispatch_group_async(组,队列,^{[nsthread sleepfortimeinterval:1.0];NSLog(@“这是队列组中的任务,编号3”);NSLog(@ "任务三:线程%@ ",[NSThread current thread]);});//队列组完成后执行的函数dispatch _ group _ notify (group,queue,{nslog (@ "队列组任务完成)。 ");});}看打印结果:image.png,我们在项目中经常遇到这样的问题。 比如我们要显示一个页面,但是这个页面有三个界面,我们需要等待三个界面的数据都返回后再显示。 此时,您可以将三个网络请求放在队列组中,等待它们完成,然后显示UI。 这里,我们举个例子。 为了合成图片,我们需要下载两张图片。两张图片都下载完之后,我们就可以合成一张图片了。 10_1.队列组案例(下载后合成图片)UI如下:ImageOne代码如下:@ property(弱,非原子)IB outlet UI ImageView * ImageOne@property(弱,非原子)IBOutlet UIImageView * imageTwo@property(弱,非原子)IBOutlet ui imageview * final image;@property(非原子,强)UIImage * image1@property(非原子,强)UIImage * image2//队列组案例:合成图片-(I action)group demo:(id)发送方{//1。创建队列组dispatch _ group _ tgroup = dispatch _ group _ create();//2.创建并发队列DISPATCH _ QUEUE _ t QUEUE = DISPATCH _ QUEUE _ create(" CONCURRENT ",DISPATCH _ QUEUE _ CONCURRENT);//3.下载图片一dispatch _ group _ async (group,queue,{ ns string * str = @ " https://Tim GSA . Baidu . com/timg?图像与图像。质量= 80 & ampsize = b9999 _ 10000 & ampsec=1601638749466。di = 92 ace 2 FFA 924 Fe 6063 e7a 221729006 b 1 & amp;imgtype = 0 & ampsrc = http % 3A % 2F % 2f pic . autov . com . cn % 2f images % 2f CMS % 2f 20119% 2 F6 % 2f 1315280805177 . jpg ";self . image1 =[self loadImage:str];dispatch _ async(dispatch _ get _ main _ queue(),^{ self . image one . image = self . image1;});});//4.下载图片二dispatch _ group _ async (group,queue,{ ns string * str = @ " https://Tim GSA . Baidu . com/timg?图像与图像。质量= 80 & ampsize = b9999 _ 10000 & ampsec=1601638873771。di = 07129 fd95c 56096 a 4282 d3b 072594491 & amp;imgtype = 0 & ampsrc = http % 3A % 2F % 2f img . 51 miz . com % 2fp review % 2f element % 2f 00% 2f 01% 2f 12% 2f 49% 2FE-1124994-5 FFE 5 AC 7 . jpg ";self . image2 =[self load image:str];dispatch _ async(dispatch _ get _ main _ queue(),^{ self . image two . image = self . image2;});});//5.合成图片dispatch _ group _ notify (group,queue,{//图形上下文打开ui Graphics BeginImageContext(CGSizeMake(300,200));//图2[self . image2 drawinrect:cgrectmake(0,0,300,200)];//图1[self . image 1 drawinrect:cgrectmake(100,50,100,100)];//获取新图片ui image * image = UIGraphicsGetImageFromCurrentImageContext();//关闭上下文UIGraphicsEndImageContext();//回到主线程,显示图片dispatch _ async(dispatch _ get _ main _ queue(),{ self . final image . image = image;NSLog(@“完成画面构图”);});});}//下载图片-(ui image *)LoadImage:(ns string *)Strurl { NSLog(@ "当前线程:%@ ",[NSThread Current thread]);NSURL * URL =[NSURL URL with string:strUrl];ns data * data =[ns data dataWithContentsOfURL:URL];ui image * image =[ui image imageWithData:data];返回图像;}结果如下:image.png的注射药片顺序。 至此,我们已经学完了GCD的基本内容。如有遗漏,欢迎留言。谢谢大家!在下一节中,我们将探讨NSOperation如何实现多线程。 祝大家生活愉快!


  • 全部评论(0)
资讯详情页最新发布上方横幅
最新发布的资讯信息
【技术支持|常见问题】响应式自适应代码(2024-03-24 14:23)
【技术支持|常见问题】1126完美滑屏版百度未授权使用地图api怎么办(2024-03-15 07:21)
【技术支持|常见问题】如何集成阿里通信短信接口(2024-02-19 21:48)
【技术支持|常见问题】算命网微信支付宝产品名称年份在哪修改?风水姻缘合婚配对_公司起名占卜八字算命算财运查吉凶源码(2024-01-07 12:27)
【域名/主机/服务器|】帝国CMS安装(2023-08-20 11:31)
【技术支持|常见问题】通过HTTPs测试Mozilla DNS {免费源码}(2022-11-04 10:37)
【技术支持|常见问题】别告诉我你没看过邰方这两则有思想的创意广告! (2022-11-04 10:37)
【技术支持|常见问题】你正确使用https了吗? [php源码](2022-11-04 10:37)
【技术支持|常见问题】安全超文本传输协议 {源码分享}(2022-11-04 10:37)
【技术支持|常见问题】借助图文解锁HTTPS原理,10分钟还原HTTPS。真的很像!建筑师必读 {源码分享}(2022-11-04 10:37)

联系我们
Q Q:375457086
Q Q:526665408
电话:0755-84666665
微信:15999668636
联系客服
企业客服1 企业客服2 联系客服
86-755-84666665
手机版
手机版
扫一扫进手机版
返回顶部