美文网首页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

相关文章

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

    在iOS开发中我们经常会遇到一起请求多个网络数据的情况…但是有些操作却是要在所有的网络数据请求结束之后才可以进行的...

  • 3. 异步编程

    异步编程和同步编程有什么区别? 同步在执行某个操作时,应用程序的主线程必须等待操作执行完成后才能继续执行。 异步在...

  • CountDownLatch的应用

    使用场景,在多线程执行完成后根据多线程执行返回值继续后续操作。代码如下 执行结果:pool-1-thread-1:...

  • Dispatch全局并发管理工具

    当我们采用全局并发队列去异步的执行某种操作的时候,或者使用了大量 concurrent queue 来执行较多任务...

  • 多线程应用:解决多个网络请求全部执行完成后统一刷新UI的操作

    场景: 现在需要执行三个接口(1001/1002/1003) ,三个接口全部执行完成后再执行刷新UI操作. 目录:...

  • GCD dispatch_barrier_async和dispa

    1、栅栏函数使用场景 异步执行两组操作,且第一组操作(多个任务)执行完成后,才开始执行第二组操作(多个任务)。 2...

  • 多线程、线程池

    多线程 多任务的概念 什么叫“多任务”呢?简单地说,就是操作系统可以同时运行多个任务。 单核CPU如何执行多任务?...

  • 异步编程

    同步与异步 同步:按代码顺序依次执行 异步:先执行同步代码,完成后再执行异步代码 事件循环与消息队列:当代码执行到...

  • generator、async函数

    以同步的方式管理异步操作(暂停执行的作用),每调用一次返回一个状态,如果是异步操作,则会等待异步操作完成后,继续后...

  • Kotlin:该如何实现多线程同步?

    问题背景需执行多线程任务:任务1、任务2并行执行;等全部执行完成后,执行任务3。 实现方式「多线程同步」。Kotl...

网友评论

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

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