多线程 -- 多任务异步执行完成后执行刷新操作

在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]);
    });
});

** ⚠️在这里为何使用队列组之后还要使用信号量-- 因为在这里队列组只能保证入组的任务执行完毕,但是在入组后的异步操作,并不会等待,需要使用信号量等待 **

  1. 任务的成功与失败回调中都必须标记信号量 dispatch_semaphore_signal(semaphore);
  2. 信号等待时间和任务数必须一致
  3. 创建的队列类型不同会有稍微区别,代码中给出了两种,可自行选择

真对信号量的情况几种情况配图:

多线程 -- 多任务异步执行完成后执行刷新操作_第1张图片
队列组- 信号量正常.png
多线程 -- 多任务异步执行完成后执行刷新操作_第2张图片
信号等待量小于任务数.png
多线程 -- 多任务异步执行完成后执行刷新操作_第3张图片
信号等待量大于任务数.png


*** 对列组方法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)如数量不对应会崩溃

此处有图:

队列组- 有序队列.png
队列组 - 全局并发队列.png

你可能感兴趣的:(多线程 -- 多任务异步执行完成后执行刷新操作)