美文网首页iOS Developer好东西小知识点
多线程 -- 多任务异步执行完成后执行刷新操作

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

作者: 一夕007 | 来源:发表于2017-07-13 16:20 被阅读77次
    在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. 创建的队列类型不同会有稍微区别,代码中给出了两种,可自行选择

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

    队列组- 信号量正常.png 信号等待量小于任务数.png 信号等待量大于任务数.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

    相关文章

      网友评论

        本文标题:多线程 -- 多任务异步执行完成后执行刷新操作

        本文链接:https://www.haomeiwen.com/subject/vomwhxtx.html