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









猜你喜欢

转载自blog.csdn.net/shichunxue/article/details/78503978