欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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到程序界面,用于显示组合后的图片;

iOS开发中如何使用GCD实现调度队列组的多线程开发

(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图片组合在一起,形成一张图片显示到屏幕上,如下图所示:

iOS开发中如何使用GCD实现调度队列组的多线程开发