您的位置:首页 > 理论基础 > 计算机网络

第02天多线程网络:(04):GCD队列组的使用

2017-04-18 00:00 127 查看
#####一、GCD队列组的使用

本次学习的知识
1.队列组
2.队列组的创建
3.队列组异步函数的使用(两种方式: 1.简单的方式。2.函数队的方式)
4.拦截通知(非阻塞拦截,阻塞拦截)
阻塞 : 当前代码没有执行完毕,下面的方法不会执行

#####二、CCD队列组的基本使用

1.队列组
dispatch_group_t


dispatch_group_t


2.创建队列组
dispatch_group_create()


dispatch_group_t group = dispatch_group_create(); // 创建一个队列组


3.队列组异步函数(简单方式)
dispatch_group_async


/**
dispatch_group_async 内部做的事情
1) 封装任务
2) 添加任务到队列中
3) 会监听任务的执行情况
参数1: 队列组
参数2: 队列
参数3: 执行任务代码
*/
dispatch_group_async(group, queue, ^{
NSLog(@"11-- %@ -- ",[NSThread currentThread]);
});


3.1队列组异步函数(函数队的方式)
dispatch_group_enter 和 dispatch_group_leave 必须要配对使用


#warning dispatch_group_enter 和 dispatch_group_leave 必须要配对使用
#pragma dispatch_group_enter
// 3.在方法后面 的异步任务 会被纳入 到队列组的监听范围
// 参数1 : 队列
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"11-- %@ -- ",[NSThread currentThread]);
#pragma dispatch_group_leave 离开队列组
// 离开群组
dispatch_group_leave(group);
});
dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"22-- %@ -- ",[NSThread currentThread]);
dispatch_group_leave(group);
});


4.队列组拦截通知方式1(非阻塞)
dispatch_notify


dispatch_notify
// 问题? 该方法是阻塞的吗? 同步的还是异步的
// 内部本身是异步的
dispatch_notify(group, queue, ^{
NSLog(@"dispatch_notify");
});


4.1队列组拦截通知方式2(阻塞)
dispatch_group_wait


/*
参数1 : 队列组
参数2 : gcd的时间
#define DISPATCH_TIME_NOW (0ull)
#define DISPATCH_TIME_FOREVER (~0ull) 死等 死都要等
*/
// 等待 死等,直到队列组中所有的任务执行完毕之后
// 本身是阻塞的 (当前代码没有执行完毕,下面的方法不会执行)
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);


案例
使用GCD队列组进行两张图片图片合并

image1、image2是全局的属性,用来保存内容,为了防止在block里面代码块一过,对象会销毁
imageView是一个200*200的图片控件,用来合并两张图片进行显示的

- (void)group3
{
/*
1.下载图片1 开启子线程
2.下载图片2 开启子线程
3.合成图片并显示图片 开启子线程
*/

// 0.获取并发队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

// 获取队列组
dispatch_group_t group = dispatch_group_create();

// 1.下载图片1 开启子线程
dispatch_group_async(group, queue,^{ // 使用队列组异步函数
//    dispatch_async(queue, ^{ // 使用异步函数
NSLog(@"download1 --- %@",[NSThread currentThread]);
// 1.1.确定url
NSURL *url = [NSURL URLWithString:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1494051566305&di=2797cce67f410ef9b76e5daef82ab8d7&imgtype=0&src=http%3A%2F%2Fi0.hdslb.com%2Fbfs%2Farchive%2F0b73ff9a3db9377d07f31964984fde836813fa33.jpg"];
// 1.2.下载二进制数据
NSData *imageData = [NSData dataWithContentsOfURL:url];
// 1.3.转换成图片
self.image1 = [UIImage imageWithData:imageData];
});

// 2.下载图片2 开启子线程
dispatch_group_async(group, queue,^{
//    dispatch_async(queue, ^{
NSLog(@"download2 --- %@",[NSThread currentThread]);
// 2.1.确定url
NSURL *url = [NSURL URLWithString:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1494051566305&di=cc44c89029d82764696f39f5cb9fa88a&imgtype=0&src=http%3A%2F%2Fimg1.ph.126.net%2FjPK4fKRr6oepN5AWcRr6Fg%3D%3D%2F1872653020156151185.jpg"];
// 2.2.下载二进制数据
NSData *imageData = [NSData dataWithContentsOfURL:url];
// 2.3.转换成图片
self.image2 = [UIImage imageWithData:imageData];
});

// 3.合成图片并显示图片 开启子线程
// 如果需要在主线程执行 那么修改一下队列的线程就行了
//    dispatch_group_notify(group, queue, ^{ // 子线程
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"combie --- %@",[NSThread currentThread]);

// 如何合并图片 (画图)?
// 3.1 创建图形上下文
#pragma 1.UIGraphicsBeginImageContext 创建图形上下文
UIGraphicsBeginImageContext(CGSizeMake(200, 200));
// 3.2 画图1 (上边)
[self.image1 drawInRect:CGRectMake(0, 0, 200, 100)]; // 图片1的位置
// 画完图可以进行释放掉
self.image1 = nil;
// 3.3 画图2 (下边)
[self.image2 drawInRect:CGRectMake(0, 100, 200, 100)]; // 图片2的位置
self.image2 = nil;

// 3.4 根据上下文 得到一张图片
#pragma 2.UIGraphicsGetImageFromCurrentImageContext 根据上下文 得到一张图片
/*
UIImage * UIGraphicsGetImageFromCurrentImageContext(void);
Description
Returns an image based on the contents of the current bitmap-based graphics context.
You should call this function only when a bitmap-based graphics context is the current graphics context. If the current context is nil or was not created by a call to UIGraphicsBeginImageContext, this function returns nil.
This function may be called from any thread of your app.
Returns
A image object containing the contents of the current bitmap graphics context.
Availability	iOS (2.0 and later), tvOS (9.0 and later), watchOS (2.0 and later)

返回一张图片
*/
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

// 3.5 关闭上下文
#pragma 3.UIGraphicsEndImageContext 关闭上下文
UIGraphicsEndImageContext();

// 3.6 更新UI 显示图片 (当前是子线程,刷新UI需要回归主线程)
//        dispatch_async(dispatch_get_main_queue(), ^{

NSLog(@"UI --- %@",[NSThread currentThread]);
self.imageView.image = image;
//        });

});

//    dispatch_release(group);// 自己创建的队列 iOS6之前需要进行释放
// 栅栏函数 只能在自己创建的队列使用, 不能使用全局并发队列

}


code

#import "ViewController.h"

@interface ViewController ()

/** 图片1 */
@property(nonatomic, strong)UIImage *image1;
/** 图片2 */
@property(nonatomic, strong)UIImage *image2;
@property (weak, nonatomic) IBOutlet UIImageView *imageView;

@end

@implementation ViewController
#pragma mark 队列组 (队列执行完毕 之后进行操作)
-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event
{
// [self group2];
[self group3];
}

#pragma mark 1.队列组的简单方式
- (void)group1
{
// 1.创建队列
// dispatch_get_global_queue 并发队列 (开启子线程进行执行)
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
#pragma 1. 队列组 dispatch_group_t
// 2.创建队列组
dispatch_group_t group = dispatch_group_create(); // 创建一个队列组 dispatch_group_create

// 3. 创建一个异步函数 (先往下走,执行下面才执行异步函数)
/**
dispatch_async 内部做的事情
1) 封装任务
2) 添加任务到队列中
// dispatch_async(queue, ^{
// NSLog(@"11-- %@ -- ",[NSThread currentThread]);
// });
*/
#pragma 2. 队列组异步函数 dispatch_group_async

/**
dispatch_group_async 内部做的事情
1) 封装任务
2) 添加任务到队列中
3) 会监听任务的执行情况

参数1: 队列组
参数2: 队列
参数3: 执行任务代码
*/

dispatch_group_async(group, queue, ^{
NSLog(@"11-- %@ -- ",[NSThread currentThread]);
});

dispatch_group_async(group,queue, ^{
NSLog(@"22-- %@ -- ",[NSThread currentThread]);
});

dispatch_group_async(group,queue, ^{
NSLog(@"33-- %@ -- ",[NSThread currentThread]);
});
#pragma 3. 队列组拦截通知 dispatch_notify
// 拦截通知 : 当队列组中所有的任务都执行完毕的时候 回进入下面这个方法
/**
参数1 : 队列组
参数2 : 队列
参数3 : 执行完毕执行的代码
*/
dispatch_notify(group, queue, ^{
NSLog(@"dispatch_notify");
});

NSLog(@"-- end --");

}

#pragma mark 2.使用函数队实现
- (void)group2
{
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);
dispatch_group_t group = dispatch_group_create();

#warning dispatch_group_enter 和 dispatch_group_leave 必须要配对使用
#pragma dispatch_group_enter
// 3.在方法后面 的异步任务 会被纳入 到队列组的监听范围
// 参数1 : 队列
dispatch_group_enter(group);

dispatch_async(queue, ^{
NSLog(@"11-- %@ -- ",[NSThread currentThread]);
#pragma dispatch_group_leave 离开队列组
// 离开群组
dispatch_group_leave(group);
});

dispatch_group_enter(group);
dispatch_async(queue, ^{
NSLog(@"22-- %@ -- ",[NSThread currentThread]);
dispatch_group_leave(group);
});

// 拦截通知
// 问题? 该方法是阻塞的吗? 同步的还是异步的
// 内部本身是异步的
// dispatch_notify(group, queue, ^{
// NSLog(@"dispatch_notify");
// });

#pragma long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);

// 拦截通知2

/**
long dispatch_group_wait(dispatch_group_t group, dispatch_time_t timeout);
Description
Waits synchronously for the previously submitted block objects to complete; returns if the blocks do not complete before the specified timeout period has elapsed.
This function waits for the completion of the blocks associated with the given dispatch group and returns when either all blocks have completed or the specified timeout has elapsed. When a timeout occurs, the group is restored to its original state.
This function returns immediately if the dispatch group is empty (there are no blocks associated with the group).
After the successful return of this function, the dispatch group is empty, and can be reused for additional blocks. See dispatch_group_async for more information.
If your app isn’t using ARC, you should call dispatch_release on a dispatch group when it’s no longer needed.
Parameters
group
The dispatch group to wait on. This parameter cannot be NULL.
timeout
When to timeout (see dispatch_time). The DISPATCH_TIME_NOW and DISPATCH_TIME_FOREVER constants are provided as a convenience.
Returns
Returns zero on success (all blocks associated with the group completed before the specified timeout) or non-zero on error (timeout occurred).
Availability iOS (4.0 and later), macOS (10.6 and later), tvOS (4.0 and later), watchOS (2.0 and later)

参数1 : 队列组
参数2 : gcd的时间

#define DISPATCH_TIME_NOW (0ull) 从现在开始
#define DISPATCH_TIME_FOREVER (~0ull) 死等 死都要等
*/
// 等待 死等,直到队列组中所有的任务执行完毕之后才能执行
// 本身是阻塞的 (当前代码没有执行完毕,下面的方法不会执行)
dispatch_group_wait(group, DISPATCH_TIME_FOREVER);
NSLog(@"-- end --");
}

- (void)group3
{
/*
1.下载图片1 开启子线程
2.下载图片2 开启子线程
3.合成图片并显示图片 开启子线程
*/

// 0.获取并发队列
dispatch_queue_t queue = dispatch_get_global_queue(0, 0);

// 获取队列组
dispatch_group_t group = dispatch_group_create();

// 1.下载图片1 开启子线程
dispatch_group_async(group, queue,^{ // 使用队列组异步函数
// dispatch_async(queue, ^{ // 使用异步函数
NSLog(@"download1 --- %@",[NSThread currentThread]);
// 1.1.确定url
NSURL *url = [NSURL URLWithString:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1494051566305&di=2797cce67f410ef9b76e5daef82ab8d7&imgtype=0&src=http%3A%2F%2Fi0.hdslb.com%2Fbfs%2Farchive%2F0b73ff9a3db9377d07f31964984fde836813fa33.jpg"];
// 1.2.下载二进制数据
NSData *imageData = [NSData dataWithContentsOfURL:url];
// 1.3.转换成图片
self.image1 = [UIImage imageWithData:imageData];
});

// 2.下载图片2 开启子线程
dispatch_group_async(group, queue,^{
// dispatch_async(queue, ^{
NSLog(@"download2 --- %@",[NSThread currentThread]);
// 2.1.确定url
NSURL *url = [NSURL URLWithString:@"https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1494051566305&di=cc44c89029d82764696f39f5cb9fa88a&imgtype=0&src=http%3A%2F%2Fimg1.ph.126.net%2FjPK4fKRr6oepN5AWcRr6Fg%3D%3D%2F1872653020156151185.jpg"];
// 2.2.下载二进制数据
NSData *imageData = [NSData dataWithContentsOfURL:url];
// 2.3.转换成图片
self.image2 = [UIImage imageWithData:imageData];
});

// 3.合成图片并显示图片 开启子线程
// 如果需要在主线程执行 那么修改一下队列的线程就行了
// dispatch_group_notify(group, queue, ^{ // 子线程
dispatch_group_notify(group, dispatch_get_main_queue(), ^{
NSLog(@"combie --- %@",[NSThread currentThread]);

// 如何合并图片 (画图)?
// 3.1 创建图形上下文
#pragma 1.UIGraphicsBeginImageContext 创建图形上下文
UIGraphicsBeginImageContext(CGSizeMake(200, 200));
// 3.2 画图1 (上边)
[self.image1 drawInRect:CGRectMake(0, 0, 200, 100)]; // 图片1的位置
// 画完图可以进行释放掉
self.image1 = nil;
// 3.3 画图2 (下边)
[self.image2 drawInRect:CGRectMake(0, 100, 200, 100)]; // 图片2的位置
self.image2 = nil;

// 3.4 根据上下文 得到一张图片
#pragma 2.UIGraphicsGetImageFromCurrentImageContext 根据上下文 得到一张图片
/*
UIImage * UIGraphicsGetImageFromCurrentImageContext(void);
Description
Returns an image based on the contents of the current bitmap-based graphics context.
You should call this function only when a bitmap-based graphics context is the current graphics context. If the current context is nil or was not created by a call to UIGraphicsBeginImageContext, this function returns nil.
This function may be called from any thread of your app.
Returns
A image object containing the contents of the current bitmap graphics context.
Availability iOS (2.0 and later), tvOS (9.0 and later), watchOS (2.0 and later)

返回一张图片
*/
UIImage *image = UIGraphicsGetImageFromCurrentImageContext();

// 3.5 关闭上下文
#pragma 3.UIGraphicsEndImageContext 关闭上下文
UIGraphicsEndImageContext();

// 3.6 更新UI 显示图片 (当前是子线程,刷新UI需要回归主线程)
// dispatch_async(dispatch_get_main_queue(), ^{

NSLog(@"UI --- %@",[NSThread currentThread]);
self.imageView.image = image;
// });

});

// dispatch_release(group);// 自己创建的队列 iOS6之前需要进行释放
// 栅栏函数 只能在自己创建的队列使用, 不能使用全局并发队列

}

@end
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  Objective-C 多线程