iOS実戦:GCDを使用して複数の画像のダウンロード制御を実現

5002 ワード

開発中は、サブスレッドに時間がかかる操作がしばしば発生し、完了したらメインスレッドに戻ってUIを同期し、メインスレッドがブロックされないようにします.複数の時間のかかる操作を同時に処理し、すべての時間のかかる操作を処理した後にUIを同期する必要がある場合があります.この場合、GCDを使用できます.
需要1
同時に2枚の図をダウンロードする
同時に2枚の画像をダウンロードする必要があります.2枚の画像がダウンロードされた後、同時に戻ります.
グループを用いた概略実装
- (void)downloadImageSuccess:(void (^)(UIImage *image1, UIImage *image2))success {
    dispatch_queue_t global_queue = dispatch_get_global_queue(0, 0);
    dispatch_group_t group = dispatch_group_create();
    
    __block UIImage *image1;
    __block UIImage *image2;
    dispatch_group_async(group, global_queue, ^{
        NSLog(@"         ");
        sleep(2);
        image1 = [UIImage new];
        NSLog(@"         ");
    });
    
    dispatch_group_async(group, global_queue, ^{
        NSLog(@"         ");
        sleep(3);
        image2 = [UIImage new];
        NSLog(@"         ");
    });
    
    dispatch_group_notify(group, dispatch_get_main_queue(), ^{
        NSLog(@"        ");
        success(image1, image2);
    });
}

需要2
ダウンロードタイムアウト時間は2秒です
画像のダウンロードタイムアウト時間を2秒に設定し、画像が2秒後にすべてダウンロードされていない場合は、完了していない画像をnilで返します.
コード実装dispatch_group_wait関数を使用します.
- (void)downloadImageSuccess:(void (^)(UIImage *image1, UIImage *image2))success {
    dispatch_queue_t global_queue = dispatch_get_global_queue(0, 0);
    dispatch_group_t group = dispatch_group_create();

    __block UIImage *image1;
    __block UIImage *image2;
    dispatch_group_async(group, global_queue, ^{
        NSLog(@"         ");
        sleep(2);
        image1 = [UIImage new];
        NSLog(@"         ");
    });

    dispatch_group_async(group, global_queue, ^{
        NSLog(@"         ");
        sleep(4);
        image2 = [UIImage new];
        NSLog(@"         ");
    });

    
    dispatch_async(global_queue, ^{
        dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC));
        dispatch_async(dispatch_get_main_queue(), ^{
            success(image1, image2);
        });
    });
}

2018-12-09 21:56:15.007222+0800 GCDDemo[12279:450516]          
2018-12-09 21:56:15.007222+0800 GCDDemo[12279:450524]          
2018-12-09 21:56:17.011723+0800 GCDDemo[12279:450516]          
2018-12-09 21:56:18.007809+0800 GCDDemo[12279:450477] , {0, 0} (null)
2018-12-09 21:56:19.008913+0800 GCDDemo[12279:450524]          

注意waitは必ずサブスレッドに配置しなければなりません.そうしないと、メインスレッドがブロックされます.
具体的にGCDを使ってダウンロードを完了する際に発生した問題
問題1:非同期タスクが制御できない
光の上のコードは、実際には複数の画像のダウンロードの同期機能を実現することはできません.システムのパッケージされたダウンロードのクラスを使用すると、このようにしか使えないからです.
    NSURLSession *session = [NSURLSession sharedSession];
    NSURLSessionDownloadTask *task = [session downloadTaskWithURL:[NSURL URLWithString:@"image"] completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
        
    }];
    [task resume];

このコードをdispatch_group_asyncに直接投げ込むと、非同期でタスクのダウンロードを開始するしかなく、タスクを同期する機能はできません.次のようになります.
    dispatch_group_async(group, global_queue, ^{
        dispatch_sync(con_queue, ^{
            // TODO
        });
    });

では、どうすればいいですか.答えはdispatch_group_enterdispatch_group_leaveの方法を使用します.具体的なシミュレーションの使用:
    dispatch_queue_t global_queue = dispatch_get_global_queue(0, 0);
    dispatch_group_t group = dispatch_group_create();

    __block UIImage *image1;
    __block UIImage *image2;
    dispatch_group_enter(group);
    dispatch_group_async(group, global_queue, ^{
        dispatch_sync(con_queue), ^{
            NSLog(@"         ");
            sleep(2);
            image1 = [UIImage new];
            NSLog(@"         ");
            dispatch_group_leave(group);
        });
    });

    dispatch_group_enter(group);
    dispatch_group_async(group, global_queue, ^{
        dispatch_sync(con_queue), ^{
            NSLog(@"         ");
            sleep(4);
            image2 = [UIImage new];
            NSLog(@"         ");
            dispatch_group_leave(group);
        });
    });

    dispatch_async(global_queue, ^{
        dispatch_group_wait(group, dispatch_time(DISPATCH_TIME_NOW, 3 * NSEC_PER_SEC));
        dispatch_async(dispatch_get_main_queue(), ^{
            success(image1, image2);
        });
    });


2018-12-09 22:23:36.918395+0800 GCDDemo[12558:492481]          
2018-12-09 22:23:36.918395+0800 GCDDemo[12558:492483]          
2018-12-09 22:23:38.923074+0800 GCDDemo[12558:492481]          
2018-12-09 22:23:39.919640+0800 GCDDemo[12558:492349] , {0, 0} (null)
2018-12-09 22:23:40.923513+0800 GCDDemo[12558:492483]          

質問2:画像のダウンロードをキャンセルする方法
SDWebImageのSDWebImageDownloaderクラスを使用すると、ダウンロードを直接キャンセルできます.またNSURLSessionDownloadTaskクラスにもcancelメソッドがあるのを見ましたが、試してみませんでした..
最後に、私のブログのアドレス:http://jabberyq.top/