iOS多图片上传

作者: 上北以北 | 来源:发表于2017-07-26 16:56 被阅读214次

    上传图片是很常见的操作,一般的做法是把本地的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呢? 哈哈,这就是该方法比递归要高级一点的地方,很简单就不展开说了,大家自己研究吧,喜欢的朋友不要忘记点赞哦!

    相关文章

      网友评论

      • e19fc75f0315:这里可以加一个中断处理。 超时以及请求关闭。
        上北以北:@银东 哈哈,现在就是的,但是那样的话会更加明显点,不用再二次判断了
        e19fc75f0315:@上北以北 这个没必要。 超时你就放在失败那个回调里边就可以。
        上北以北:@银东 恩恩,这点我倒是忽略了,最好是加个超时回调的block,比较灵活,毕竟每个人对中断后的处理是不一样的😀

      本文标题:iOS多图片上传

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