dispatch_group实践,AFN3.0多个网络请求

dispatch_group实践,AFN3.0多个网络请求

      在实际开发过程中经常会有在一个页面有多个网络请求,页面UI需要在所有网络请求全部回来的情况下更新。先简单看一个具体的问题:

页面有三个网络请求a、b、c。三个网络请求都成功的情况下刷新UI,有一个失败就认为请求失败,不进行UI刷新。

目前想到的方法

  • 添加标识进行判断是否所有的网络请求都是成功的
  • 通过信号量判断
  • 直接使用dispatch_group(当然也可以结合信号量

这里就简单使用dispatch_group来实践一下:

先简单了解一下必须的东西



常用方法

1、dispatch_group_create 创建一个调度任务组

2、dispatch_group_async 把一个任务异步提交到任务组里

3、dispatch_group_enter/dispatch_group_leave 这种方式用在不使用dispatch_group_async来提交任务,且必须配合使用

4、dispatch_group_notify 用来监听任务组事件的执行完毕

5、dispatch_group_wait 设置等待时间



实现一个dispatch_group_async 简单的例子

      基本需求和文章前面的需求差不多,task 1task 2task 3task 4四个任务,task 4要在task 1task 2task 3执行完成之后在执行。
先看一下代码:


    - (void)testDisGroup {
        dispatch_queue_t demoQuene = dispatch_queue_create("demoQuene", DISPATCH_QUEUE_CONCURRENT);
        dispatch_group_t group = dispatch_group_create();

        NSLog(@"\n\nmain thread %@\n\n",[NSThread currentThread]);

        dispatch_group_async(group, demoQuene, ^{
            sleep(arc4random_uniform(5));
            NSLog(@"task 1  %@",[NSThread currentThread]);
        });

        dispatch_group_async(group, demoQuene, ^{
            sleep(arc4random_uniform(5));
            NSLog(@"task 2  %@",[NSThread currentThread]);
        });

        dispatch_group_async(group, demoQuene, ^{
            sleep(arc4random_uniform(5));
            NSLog(@"task 3  %@",[NSThread currentThread]);
        });

        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"task 4  %@",[NSThread currentThread]);
        });
    }

看一下结果:


图片名称

当然task 1task 2task 3完成的顺序不是固定,最后是task 4,需要看系统怎么分配资源。



升级一下dispatch_group_async 的例子

在上面任务的基础上添加一个需求,就是task 2task 3要有一个顺序,比如task 2要在task 3执行完成之后才能执行。
看一下代码(当然实现的方案很多,这只是个例子):


    - (void)testDisGroup {
        dispatch_queue_t demoQueneCONCURRENT = dispatch_queue_create("demoQuene", DISPATCH_QUEUE_CONCURRENT);
        dispatch_queue_t demoQueneSERIAL = dispatch_queue_create("demoQuene", DISPATCH_QUEUE_SERIAL);
        dispatch_group_t group = dispatch_group_create();

        NSLog(@"\n\nmain thread %@\n\n",[NSThread currentThread]);

        dispatch_group_async(group, demoQueneCONCURRENT, ^{
            sleep(arc4random_uniform(5));
            NSLog(@"task 1  %@",[NSThread currentThread]);
        });

        dispatch_group_async(group, demoQueneSERIAL, ^{
            sleep(arc4random_uniform(5));
            NSLog(@"task 3  %@",[NSThread currentThread]);
        });

        dispatch_group_async(group, demoQueneSERIAL, ^{
            sleep(arc4random_uniform(5));
            NSLog(@"task 2  %@",[NSThread currentThread]);
        });

        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"task 4  %@",[NSThread currentThread]);
        });
    }

执行结果:


图片名称

另一个结果:


图片名称

当然这个结果也存在多种情况,不变的是task 4要在task 1task 2task 3执行完成之后在执行,task 2要在task 3执行完成之后才能执行。其他的顺序是不确定的。



使用dispatch_group_enter/dispatch_group_leave 复写一下第一个例子


    -(void)testDisGroupEnterAndLeave {
        dispatch_queue_t demoQueneCONCURRENT = dispatch_queue_create("demoQuene2", DISPATCH_QUEUE_CONCURRENT);
        dispatch_group_t group = dispatch_group_create();

        dispatch_group_enter(group);
        dispatch_async(demoQueneCONCURRENT, ^{
            NSLog(@"task 1  %@",[NSThread currentThread]);
            sleep(arc4random_uniform(5));
            dispatch_group_leave(group);
        });

        dispatch_group_enter(group);
        dispatch_async(demoQueneCONCURRENT, ^{
            NSLog(@"task 2  %@",[NSThread currentThread]);
            sleep(arc4random_uniform(5));
            dispatch_group_leave(group);
        });

        dispatch_group_enter(group);
        dispatch_async(demoQueneCONCURRENT, ^{
            NSLog(@"task 3  %@",[NSThread currentThread]);
            sleep(arc4random_uniform(5));
            dispatch_group_leave(group);
        });

        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"task 4  %@",[NSThread currentThread]);
            sleep(arc4random_uniform(5));
        });
    }

运行结果:


图片名称

另一结果:


图片名称



使用dispatch_group_enter/dispatch_group_leave 复写一下第二个例子

上代码:


    -(void)testDisGroupEnterAndLeave {
        dispatch_queue_t demoQueneCONCURRENT = dispatch_queue_create("demoQuene2", DISPATCH_QUEUE_CONCURRENT);
        dispatch_queue_t demoQueneSERIAL = dispatch_queue_create("demoQuene3", DISPATCH_QUEUE_SERIAL);
        dispatch_group_t group = dispatch_group_create();

        dispatch_group_enter(group);
        dispatch_async(demoQueneCONCURRENT, ^{
            NSLog(@"task 1  %@",[NSThread currentThread]);
            sleep(arc4random_uniform(5));
            dispatch_group_leave(group);
        });

        dispatch_group_enter(group);
        dispatch_async(demoQueneSERIAL, ^{
            NSLog(@"task 3  %@",[NSThread currentThread]);
            sleep(arc4random_uniform(5));
            dispatch_group_leave(group);
        });

        dispatch_group_enter(group);
        dispatch_async(demoQueneSERIAL, ^{
            NSLog(@"task 2  %@",[NSThread currentThread]);
            sleep(arc4random_uniform(5));
            dispatch_group_leave(group);
        });

        dispatch_group_notify(group, dispatch_get_main_queue(), ^{
            NSLog(@"task 4  %@ \n\n\n.",[NSThread currentThread]);
            sleep(arc4random_uniform(5));
        });
    }

结果(两次结果写在一起了):


图片名称



开始实战

      还是文章开始的那道题现在看一下

页面有三个网络请求a、b、c。三个网络请求都成功的情况下刷新UI,有一个失败就认为请求失败,不进行UI刷新。


    @interface TestThread () {
        dispatch_group_t _group;
    }

    @end

    @implementation TestThread

    - (void)p_loadBannerData {
        dispatch_group_enter(_group);
       AdvBannerApi *bannerApi = [[AdvBannerApi alloc] initWithAdvType:AdvTypeBanner];
        [bannerApi startWithSuccessBlock:^(ApiResult * _Nullable result) {
            NSLog(@"task 1 success");
            dispatch_group_leave(_group);
        } failureBlock:^(NSError * _Nullable error) {
            NSLog(@"task 1 failure");
            dispatch_group_leave(_group);
        }];
    }

    - (void)p_loadCourseListData {
        dispatch_group_enter(_group);
        QualityCourseApi *courseApi = [[QualityCourseApi alloc] initWithStart:@"0"
                                                                        count:@"20"];
        [courseApi startWithSuccessBlock:^(ApiResult * _Nullable result) {
            NSLog(@"task 2 success");
            dispatch_group_leave(_group);
        } failureBlock:^(NSError * _Nullable error) {
            NSLog(@"task 2 failure");
            dispatch_group_leave(_group);
        }];
    }

    - (void)p_loadLivingLessonData {
        dispatch_group_enter(_group);
        LessonForecastApi *api = [[LessonForecastApi alloc] init];
        [api startWithSuccessBlock:^(ApiResult * _Nullable result) {
            NSLog(@"task 3 success");
            dispatch_group_leave(_group);
        } failureBlock:^(NSError * _Nullable error) {
            NSLog(@"task 3 failure");
            dispatch_group_leave(_group);
        }];
    }

    - (void)reloadUI {
        NSLog(@"task 4");
    }

    -(void)disGroupEnterAndLeave {
        _group = dispatch_group_create();

        [self p_loadBannerData];
        [self p_loadCourseListData];
        [self p_loadLivingLessonData];

        dispatch_group_notify(_group, dispatch_get_main_queue(), ^{
            NSLog(@"run task 4 %@",[NSThread currentThread]);
            [self reloadUI];
        });
    }

    @end

看一下结果:


图片名称



其他的写法就一一实现了。现在看一下错误的写法


    @interface TestThread () {
        dispatch_group_t _group;
    }

    @end

    @implementation TestThread

    - (void)p_loadBannerData {
       AdvBannerApi *bannerApi = [[AdvBannerApi alloc] initWithAdvType:AdvTypeBanner];
        [bannerApi startWithSuccessBlock:^(ApiResult * _Nullable result) {
            NSLog(@"task 1 success");
        } failureBlock:^(NSError * _Nullable error) {
            NSLog(@"task 1 failure");
        }];
    }

    - (void)p_loadCourseListData {
        QualityCourseApi *courseApi = [[QualityCourseApi alloc] initWithStart:@"0"
                                                                        count:@"20"];
        [courseApi startWithSuccessBlock:^(ApiResult * _Nullable result) {
            NSLog(@"task 2 success");
        } failureBlock:^(NSError * _Nullable error) {
            NSLog(@"task 2 failure");
        }];
    }

    - (void)p_loadLivingLessonData {
        LessonForecastApi *api = [[LessonForecastApi alloc] init];
        [api startWithSuccessBlock:^(ApiResult * _Nullable result) {
            NSLog(@"task 3 success");
        } failureBlock:^(NSError * _Nullable error) {
            NSLog(@"task 3 failure");
        }];
    }

    - (void)reloadUI {
        NSLog(@"task 4");
    }

    -(void)disGroup {
        dispatch_queue_t demoQueneCONCURRENT = dispatch_queue_create("demoQuene", DISPATCH_QUEUE_CONCURRENT);
        _group = dispatch_group_create();

        dispatch_group_async(_group, demoQueneCONCURRENT, ^{
            [self p_loadBannerData];
        });

        dispatch_group_async(_group, demoQueneCONCURRENT, ^{
            [self p_loadCourseListData];
        });

        dispatch_group_async(_group, demoQueneCONCURRENT, ^{
            [self p_loadLivingLessonData];
        });

        dispatch_group_notify(_group, dispatch_get_main_queue(), ^{
            NSLog(@"run task 4 %@",[NSThread currentThread]);
            [self reloadUI];
        });
    }

    @end

看一下结果:


图片名称



      很显然结果是错误的,task 4最先得出了结果,主要因为


    dispatch_group_async(_group, demoQueneCONCURRENT, ^{
    });

开启了一个新线程,然后

                [self p_loadBannerData];

网络请求又开启了一个线程。


    dispatch_group_async(_group, demoQueneCONCURRENT, ^{
    });

开启的3个新线程执行完之后执行task 4。网络耗时的操作才执行。然后就………………错了。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章