美文网首页iOS开发之常用技术点
iOS实战:使用GCD实现多张图片的下载控制

iOS实战:使用GCD实现多张图片的下载控制

作者: Jabber_YQ | 来源:发表于2018-12-09 22:38 被阅读5次

在开发过程中,经常会遇到耗时的操作需要放到子线程中,完成后再返回到主线程中同步UI,以防阻塞主线程。有时候,可能需求是要同时处理多个耗时操作,在处理完所有耗时操作后再同步UI,这时候就可以使用到GCD了。

需求1

同时下载两张图

需要同时下载两张图片,在两张图片都下载完成后,同时返回。

使用group的大致实现

- (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秒后没有全部下载完成,那么没完成的图片用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] <UIImage: 0x60000186a450>, {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] <UIImage: 0x600003ffb100>, {0, 0} (null)
2018-12-09 22:23:40.923513+0800 GCDDemo[12558:492483] 第二张图片下载完成

问题2:如何取消图片下载任务

其实使用SDWebImage的SDWebImageDownloader类可以直接取消下载操作。
同时我看到NSURLSessionDownloadTask类中也有cancel方法,但是我没试。。。


最后,我的博客地址:http://jabberyq.top/

相关文章

网友评论

    本文标题:iOS实战:使用GCD实现多张图片的下载控制

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