iOS开发中如何使用GCD实现调度队列组的多线程开发
程序员文章站
2022-03-08 15:22:18
iOS开发中如何使用GCD实现调度队列组的多线程开发,假设有一个音乐应用,如果要执行多个下载歌曲的任务,这些耗时的任务会被放到多个线程上异步执行,直到全部的歌曲下载完成,弹出一个提...
iOS开发中如何使用GCD实现调度队列组的多线程开发,假设有一个音乐应用,如果要执行多个下载歌曲的任务,这些耗时的任务会被放到多个线程上异步执行,直到全部的歌曲下载完成,弹出一个提示框来通知用户歌曲已下载完成。
针对这个应用场景,可以考虑使用队列组。一个队列组可以将多个block组成一组,用于监听这一组任务是否全部完成,指导关联的任务全部完成后再发出通知以执行其他的操作。iOS提供了如下的函数开始用队列组。
(1)创建队列组
要想使用队列组,首先需要创建一个队列组对象,可以通过dispatch_group_create()函数来创建,它的定义格式如下:
dispatch_group_t dispatch_group_create(void);在上述格式中,该函数无需传入任何参数,其返回值是dispatch_group_t类型的。
(2)调用队列组
创建了dispatch_group_t对象后,可以使用dispatch_group_async()函数将block提交至一个队列,同时将这些block添加到一个组里面,函数格式如下:
void dispatch_group_async(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);在上述格式中,该函数没有返回值,它需要传入3个参数,第1个参数是创建的队列组,第2个参数是将要添加到的队列,第3个参数是将要执行的代码块。需要注意的是,该函数的名称有一个async标志,表示这个组会异步地执行这些代码块。
(3)通知
当全部的任务执行完成后,通知执行其他的操作,通过dispatch_group_notify()函数来通知,它的定义格式如下:
void dispatch_group_notify(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block);在上述定义格式中,该函数需要传入3个参数,第1个参数表示创建的队列组,第2个参数表示其他任务要添加到的队列,第3个参数表示要执行的其他代码块。
接下来通过模拟一个需求来展示调度队列组,就是从网上加载两张图片,进行组合后,最终显示到一个ImageView上。根据这个需求,通过代码完成相应的逻辑,具体步骤如下:
(1)新建一个SingleViewApplication工程,命名为08-Dispatch Group;
(2)进入Main.StoryBoard,从对象库中拖拽一个ImageView到程序界面,用于显示组合后的图片;
(3)通过拖拽的方式,将ImageView在viewController.m文件的类扩展中进行属性的声明;
(4)单击屏幕,依次从网络上加载两张图片,直到这两张图片下载完成,将这两张图片进行组合,最终回到主线程上显示,代码如下:
#import "ViewController.h" //宏定义全局并发队列 #define global_queue dispatch_get_global_queue(0,0) //宏定义主队列 #define main_queue dispatch_get_main_queue() @interface ViewController () @property (weak, nonatomic) IBOutlet UIImageView *imageView; @end @implementation ViewController -(void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event { [self groupImage]; } /** *使用队列组组合图片 */ dispatch_group_t dispatch_group_create(void); void dispatch_group_notify(dispatch_group_t group,dispatch_queue_t queue,dispatch_block_t block); -(void)groupImage { //1、创建一个队列组和队列 dispatch_group_t group=dispatch_group_create(); //2、下载第1张图片 __block UIImage *image1=nil;//定义了__block修饰的一个属性,能在block中修改变量 dispatch_group_async(group, global_queue,^{ image1=[self downloadImage:@"https://ss0.bdstatic.com/70cFvHSh_Q1YnxGkpoWK1HF6hhy/it/u=4133347000,1310938944&fm=27&gp=0.jpg"]; }); //3、下载第2张图片 __block UIImage *image2=nil;//定义了__block修饰的另一个属性,能在block中修改变量 dispatch_group_async(group, global_queue,^{ image2=[self downloadImage:@"https://ss1.bdstatic.com/70cFuXSh_Q1YnxGkpoWK1HF6hhy/it/u=1322912466,2607748595&fm=27&gp=0.jpg"]; }); //4、合并图片 dispatch_group_notify(group, global_queue, ^{ //4、1开启一个位图上下文 UIGraphicsBeginImageContextWithOptions(image1.size, NO, 0.0); //4、2绘制第1张图片 CGFloat image1W=image1.size.width; CGFloat image1H=image1.size.height; [image1 drawInRect:CGRectMake(0, 0, image1W, image1H)]; //4、3绘制第2张图片 CGFloat image2W=image2.size.width*0.3; CGFloat image2H=image2.size.height*0.3; CGFloat image2Y=image1H-image2H; [image2 drawInRect:CGRectMake(140, image2Y, image2W, image2H)]; //4、4得到上下文的图片 UIImage *fullImage=UIGraphicsGetImageFromCurrentImageContext(); //4、5结束上下文 UIGraphicsEndImageContext(); //4、6回到主线程显示图片 dispatch_async(main_queue,^{ self.imageView.image=fullImage; }); }); } //封装一个方法,只要传入一个URL参数,就返回一张网络上下载的图片 -(UIImage *)downloadImage:(NSString *)urlStr{ NSURL *imageUrl=[NSURL URLWithString:urlStr]; NSData *data=[NSData dataWithContentsOfURL:imageUrl]; return [UIImage imageWithData:data]; } - (void)viewDidLoad { [super viewDidLoad]; // Do any additional setup after loading the view, typically from a nib. } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; // Dispose of any resources that can be recreated. } @end运行程序,程序运行成功后,单击模拟器屏幕,可见第1张人物图片和第二张百度logo图片组合在一起,形成一张图片显示到屏幕上,如下图所示: