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。網絡耗時的操作才執行。然後就………………錯了。

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