在iOS开发中我们经常会遇到一起请求多个网络数据的情况…但是有些操作却是要在所有的网络数据请求结束之后才可以进行的….比如说刷新控件收回.或者某些UI控件的更新..这种情况就不能单纯的在某一条网络请求结束后的block里操作了.一涉及到异步,GCD的强大之处就体现出来了..先上代码:
*** 对列组与信号量 ***
//信号量
dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);
//队列组
dispatch_group_t group = dispatch_group_create();
//创建队列 - 串行队列与全局并发队列择一即可
// 使用串行队列进行网络请求 -- 网络请求的开始无序,且在同一线程
dispatch_queue_t queue = dispatch_queue_create("www.baidu.com", DISPATCH_QUEUE_SERIAL);
// 使用并发队列进行网络请求 -- 网络请求的开始无序,且线程不固定
queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
//任务一
dispatch_group_async(group, queue, ^{
// 无论成功或者失败都要对信号量进行标记
NSLog(@"此次请求线程是111111:%@",[NSThread currentThread]);
[[AFHTTPSessionManager manager] POST:@"www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_semaphore_signal(semaphore);
NSLog(@"success 此次返回的是111111 线程是:%@",[NSThread currentThread]);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
dispatch_semaphore_signal(semaphore);
NSLog(@"failure 此次返回的是111111 线程是:%@",[NSThread currentThread]);
}];
});
//任务二
dispatch_group_async(group, queue, ^{
NSLog(@"此次请求线程是222222:%@",[NSThread currentThread]);
[[AFHTTPSessionManager manager] POST:@"www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_semaphore_signal(semaphore);
NSLog(@"success 此次返回的是222222 线程是:%@",[NSThread currentThread]);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
dispatch_semaphore_signal(semaphore);
NSLog(@"failure 此次返回的是222222 线程是:%@",[NSThread currentThread]);
}];
});
//任务三
dispatch_group_async(group, queue, ^{
NSLog(@"此次请求线程是333333:%@",[NSThread currentThread]);
[[AFHTTPSessionManager manager] POST:@"www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_semaphore_signal(semaphore);
NSLog(@"success 此次返回的是333333 线程是:%@",[NSThread currentThread]);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
// 模拟网络延迟
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.0 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
dispatch_semaphore_signal(semaphore);
NSLog(@"failure 此次返回的是333333 线程是:%@",[NSThread currentThread]);
});
}];
});
// 所有网络请求结束后会来到这个方法
dispatch_group_notify(group, queue, ^{
//3个任务,3个信号等待.
// 这里信号等待需要与实际任务数相同 -- 若此处信号等待数量多于任务数(其实是任务成功或者失败后标记的信号量总数) 则后续代码永远不会被执行,若此处信号等待数量少于任务数,则会提前执行
NSLog(@"当前线程是:%@",[NSThread currentThread]);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
// dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
//这里就是所有异步任务请求结束后执行的代码 -- UI操作需要回到主线程
dispatch_async(dispatch_get_main_queue(), ^{
// 刷新UI
NSLog(@"主线程刷新UI 线程是:%@",[NSThread currentThread]);
});
});
** ⚠️在这里为何使用队列组之后还要使用信号量-- 因为在这里队列组只能保证入组的任务执行完毕,但是在入组后的异步操作,并不会等待,需要使用信号量等待 **
- 任务的成功与失败回调中都必须标记信号量
dispatch_semaphore_signal(semaphore);
- 信号等待时间和任务数必须一致
- 创建的队列类型不同会有稍微区别,代码中给出了两种,可自行选择
真对信号量的情况几种情况配图:
*** 对列组方法2 ***
dispatch_group_t group = dispatch_group_create();
//创建队列 - 串行队列与全局并发队列择一即可
// 使用串行队列进行网络请求 -- 网络请求的开始无序,且在同一线程
dispatch_queue_t queue = dispatch_queue_create("www.baidu.com", DISPATCH_QUEUE_SERIAL);
// 使用并发队列进行网络请求 -- 网络请求的开始无序,且线程不固定
// queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
NSLog(@"此次请求线程是111111:%@",[NSThread currentThread]);
// 网络请求一
[[AFHTTPSessionManager manager] POST:@"www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_group_leave(group);
NSLog(@"success 此次返回的是111111 线程是:%@",[NSThread currentThread]);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
dispatch_group_leave(group);
NSLog(@"failure 此次返回的是111111 线程是:%@",[NSThread currentThread]);
}];
});
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
NSLog(@"此次请求线程是222222:%@",[NSThread currentThread]);
// 网络请求二
[[AFHTTPSessionManager manager] POST:@"www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_group_leave(group);
NSLog(@"success 此次返回的是222222 线程是:%@",[NSThread currentThread]);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
dispatch_group_leave(group);
NSLog(@"failure 此次返回的是222222 线程是:%@",[NSThread currentThread]);
}];
});
dispatch_group_enter(group);
dispatch_group_async(group, queue, ^{
NSLog(@"此次请求线程是333333:%@",[NSThread currentThread]);
// 网络请求三
[[AFHTTPSessionManager manager] POST:@"www.baidu.com" parameters:nil progress:nil success:^(NSURLSessionDataTask * _Nonnull task, id _Nullable responseObject) {
dispatch_group_leave(group);
NSLog(@"success 此次返回的是333333 线程是:%@",[NSThread currentThread]);
} failure:^(NSURLSessionDataTask * _Nullable task, NSError * _Nonnull error) {
dispatch_group_leave(group);
NSLog(@"failure 此次返回的是333333 线程是:%@",[NSThread currentThread]);
}];
});
// 所有网络请求结束后会来到这个方法
dispatch_group_notify(group, queue, ^{
NSLog(@"所有网络请求完毕1 线程是:%@",[NSThread currentThread]);
dispatch_async(dispatch_get_main_queue(), ^{
// 刷新UI
NSLog(@"主线程刷新UI 线程是:%@",[NSThread currentThread]);
});
});
在队列组的使用中,创建的队列不同,也会稍微有些区别:
- 创建串行队列 -- 网络请求的开始无序,且在同一线程
- 创建全局并发队列 -- 网络请求的开始无序,且线程不固定
- 入组和出组必须和任务数相对应 -
dispatch_group_enter(group)
和dispatch_group_leave(group)
如数量不对应会崩溃
此处有图: