为了账号安全,请及时绑定邮箱和手机立即绑定

iOS多图片上传

标签:
Html5

上传图片是很常见的操作,一般的做法是把本地的file上传到后台换取网址,但是如果是同时上传多张图片时我们怎么知道什么时候全部的图片都换取完成了呢?
比较好想到的方法是递归式的上传,即在第一张图上传完成后递归调用上传第二张,依次类推,使用这种方法实现并发是非常困难的,如果只是单张依次上传,那么这种方法是可行的,但是未免会觉得有点不太舒服。

接下来我们说第二种方法,利用线程阻塞去控制上传
其原理很简单,用信号量来控制顺序

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);

dispatch_async(queue, ^{        for (int i = 0; i < 3; i ++) {
            dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
                NSLog(@"完成任务——%d",i);
                dispatch_semaphore_signal(semaphore);
            });
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        }
        NSLog(@"任务全部执行完成");
    });

semaphore 为信号量,通过信号量去控制任务的加载
主要通过两个方法:dispatch_semaphore_signal() 和 dispatch_semaphore_wait();
第一个方法会使信号量加1
第二个方法会使信号量减1
当信号量为0时,第二个方法会线程阻塞不再向下执行,直到信号量不为0

然后我们回头看一下代码,我们把循环中的任务拆开如下

    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);    
dispatch_async(queue, ^{
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{                NSLog(@"完成任务——1");
                dispatch_semaphore_signal(semaphore);
            });
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);

        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{                NSLog(@"完成任务——2");
                dispatch_semaphore_signal(semaphore);
            });
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        
        dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{                NSLog(@"完成任务——3");
                dispatch_semaphore_signal(semaphore);
            });
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);        NSLog(@"任务全部执行完成");
    });

我们延迟两秒做为任务的执行时间
那么任务会最先执行到dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
由于我们开始创建的信号量为0,所以此时线程被阻塞,不会再向下执行任务2

当两秒以后,任务一执行到方法 dispatch_semaphore_signal(semaphore); 信号量加1,此时任务等待被唤醒,由于此时信号量为1,所以线程阻塞解除,程序向下执行到任务2,依次类推,就实现了任务一个一个按顺序完成的操作

有了这些方法,那么我们就可以把该方法封装到上传图片的网络请求中去,下面是我的封装方法,大家可以借鉴一下

//上传图片组+ (dispatch_semaphore_t)imageToGroupUrl:(NSString *)url images:(NSArray <UIImage *>*)images
                                netType:(AppNetType)type
                              parameter:(NSDictionary *)parameter
                               pageInfo:(NSString *)page
                         uploadProgress:(void (^)(NSProgress *uploadProgress))progress
                                success:(void (^)(NSURLSessionDataTask *task, id responseObject))success
                                failure:(void (^)(NSURLSessionDataTask *task, NSError *error, id responseObject))failure
                                 finish:(void (^)(void))finish {
    
    __weak typeof(self) weakSelf = self;
    dispatch_semaphore_t semaphore = dispatch_semaphore_create(0);    dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);    dispatch_async(queue, ^{
        __strong typeof(weakSelf) strongSelf = weakSelf;        for (UIImage *image in images) {
            [strongSelf imageToUrl:url image:image netType:type parameter:parameter pageInfo:page uploadProgress:^(NSProgress *uploadProgress) {                if (progress) {
                    progress(uploadProgress);
                }
            } success:^(NSURLSessionDataTask *task, id responseObject) {                if (success) {
                    success(task, responseObject);
                }
                
            } failure:^(NSURLSessionDataTask *task, NSError *error, id responseObject) {                if (failure) {
                    failure(task, error, responseObject);
                }
                
            } finish:^(NSURLSessionDataTask *task, NSError *error, id responseObject) {
                dispatch_semaphore_signal(semaphore);
            }];
            dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
        }        dispatch_async(dispatch_get_main_queue(), ^{            if (finish) {
                finish();
            }
        });
    });    
    return semaphore;
}

其中imageToUrl:image:netType:parameter:pageInfo:uploadProgress:success:failure:finish:方法是我封装上传图片的方法,使用AFNetWorking很简单就不贴出来了,大家换成自己的方法就行了
其中的block:
success为每张上传成功后的回调
finish 即为当所有图片全部上传成功后的回调

那么要是我们一开始创建的信号量不为0呢? 哈哈,这就是该方法比递归要高级一点的地方,很简单就不展开说了,大家自己研究吧。



作者:上北以北
链接:https://www.jianshu.com/p/3453c6928e33


点击查看更多内容
TA 点赞

若觉得本文不错,就分享一下吧!

评论

作者其他优质文章

正在加载中
  • 推荐
  • 评论
  • 收藏
  • 共同学习,写下你的评论
感谢您的支持,我会继续努力的~
扫码打赏,你说多少就多少
赞赏金额会直接到老师账户
支付方式
打开微信扫一扫,即可进行扫码打赏哦
今天注册有机会得

100积分直接送

付费专栏免费学

大额优惠券免费领

立即参与 放弃机会
意见反馈 帮助中心 APP下载
官方微信

举报

0/150
提交
取消