美文网首页iOS开发
iOS GCD多线程实现并发上传多个本地文件

iOS GCD多线程实现并发上传多个本地文件

作者: huxinwen | 来源:发表于2019-05-24 14:59 被阅读0次

多线程编程是软件工程是必备的基础技能之一,对于iOS开发,多线程的技术有很多,有最原始的pthread,面向对象的NSThread,NSOperation,以及被广泛开发者喜爱的GCD,之所以这样,因为它相较于其他,更轻量级,以及简便的api接口等等。

今天这里对于GCD的API所有的接口没有过多的描述,主要选择dispatch_group_t(组队列)和dispatch_semaphore_t(信号量)的简单用法及运用他们做了一个简单实用的同时上传多个本地文件的工具进行论述。

一、dispatch_group_t:

1、概念:就是将多个任务同时提交到同一个队列中执行。

并发队列异步执行

2、比如我们有一种需求,就是只有当任务1,2完成了,才能执行3任务,我们有很多方案,比如NSOperation的队列依赖,我们下面要介绍的dispatch_semaphore_t(信号量),还有dispatch_barrier(栈栏)等等,这里要将的是dispatch_group_notify:

dispatch_group_notify

这里需要注意的是, dispatch_group_enter()和 dispatch_group_leave()需要一一对应,否则会发生crash。

当然除了可以异步添加到组并发队列中,也可以同步添加,还可以添加到串行队列中,这里就不一一列举了,你们可以试试。

二、dispatch_semaphore_t信号量:

1、概念:信号量基于计数器的一种多线程同步机制。在多个线程访问共有资源时候,会因为多线程的特性而引发数据出错的问题。

2、原理:先设置一个信号总量,如果信号总量的整形参数是0 ,那么就是没有资源需要等待,我们如果下面执行dispatch_semaphore_wait() 操作,那么相当于线程拥堵,执行信号-1 操作,如果现在是绿灯通行状态,我们会设置 dispatch_semaphore_signal()信号,执行一个信号+1 操作,告诉当前线程,有一个信号可以释放了。

最大并发数为3

三、多个本地文件上传简易工具:

1、这个工具就是基于上述两个API的技术,将上传的任务添加到group中,然后通过dispatch_semaphore_t信号量来控制最大并发数,默认3,外面可以设置;

2、封装了一个fileModel类,里面包含本地路径、上传的状态、远端路径、上传任务;

3、可以多次添加任务,重复添加同一个本地文件,只会上传一次,上传缓存uploadDic是一个以本地文件路径为key,file model为value的;

4、上传失败后,回将对应的状态标记为上传失败,将是否需要重试上传标记为yes,并在第一次所有的图片上传完成后出发,最多重试3次;

5、可以中途取消上传任务,通过NSURLSessionUploadTask实现。

6、当所有的任务(包括重试任务)完成后,通过dispatch_group_notify通知所有文件上传完成后,block回调NSArray<UploadFileModel*>。

工具整体架构 filemodel类

UploadFilesTool.m代码如下:

-(instancetype)init{

    if(self= [superinit]) {

        self.semo = dispatch_semaphore_create(self.maxQueueCount);

        self.queue = dispatch_queue_create("HXWUPLOADQUEUE", DISPATCH_QUEUE_CONCURRENT);

        self.group = dispatch_group_create();

        self.needRestart=NO;

        self.lock= [NSLocknew];

        self.reUploadCount=3;

    }

    return self;

}

///第一次提交待上传的本地文件路径集合

- (void)startLocalFilePaths:(NSArray*)filePaths completion:(CompletionHandler)handler{

    if(handler) {

        self.handler= handler;

    }

    for(NSString* filePathinfilePaths) {

        UploadFileModel* model = [self.uploadDicobjectForKey:filePath];

        if(!model) {

            model = [UploadFileModelnew];

            model.state=UploadStateWaiting;

            model.originFilePath= filePath;

            model.remoteUrl=@"";

            [self.uploadDicsetObject:modelforKey:filePath];

        }

        ///取消了,再次添加到上传队列,设置为待上传状态

        if([model.remoteUrlisEqualToString:@""] && model.state==UploadStateCancel) {

            [self updateMode:model state:UploadStateWaiting];

        }

    }

    [self startUpload];

}

///中途提交待上传的本地文件路径集合

- (void)addLocalFilePaths:(NSArray*)filePaths{

    [self startLocalFilePaths:filePaths completion:nil];

}

///取消上传

- (void)cancelUploadLocalFilePaths:(NSArray*)filePaths{

        for(NSString* filePathinfilePaths) {

            UploadFileModel* model = [self.uploadDicobjectForKey:filePath];

            if(model) {///置为取消状态,并取消任务

                [self updateMode:model state:UploadStateCancel];

                if(model.task) {

                    [model.taskcancel];

                }

            }

        }

}

///开始上传

- (void)startUpload{

    [self.locklock];

    if (self.needRestart) {

        self.needRestart=NO;

    }

    [self.lockunlock];

    __weaktypeof(self) weakSelf =self;

    [self.uploadDic.allValuesenumerateObjectsUsingBlock:^(UploadFileModel*  _Nonnullobj,NSUIntegeridx,BOOL*_Nonnullstop) {

        if (obj.state == UploadStateWaiting ||obj.state == UploadStateFailed) {

            obj.state=UploadStateUploading;

            ///记得enter跟leave一一对应

            dispatch_group_enter(weakSelf.group);

            dispatch_group_async(weakSelf.group, weakSelf.queue, ^{

                ///信号量减1,小于0等待

                dispatch_semaphore_wait(weakSelf.semo,DISPATCH_TIME_FOREVER);

                obj.task= [weakSelf.delegateuploadFile:obj.originFilePathsuceed:^(NSString*remoteUrl) {

                    [weakSelfupdateMode:objstate:UploadStateSucessed];

                    obj.remoteUrl= remoteUrl;

                    obj.task=nil;///任务置空

                    ///信号量加1

                    dispatch_semaphore_signal(weakSelf.semo);

                    ///记得enter跟leave一一对应

                    dispatch_group_leave(weakSelf.group);

                }failed:^(NSString*des,NSIntegercode) {

                    if(obj.state==UploadStateUploading) {

                        ///不是主动取消,设置为failed

                        [weakSelfupdateMode:objstate:UploadStateFailed];

                    }

                    obj.task=nil;///任务置空

                    ///信号量加1

                    dispatch_semaphore_signal(weakSelf.semo);

                    ///记得enter跟leave一一对应

                    dispatch_group_leave(weakSelf.group);

                }progress:^(doubleprogress) {

                    ///备用

                }];

            });

        }

    }];

    ///全部上传完成通知结果

    dispatch_group_notify(self.group, dispatch_get_main_queue(), ^{

        ///上传失败,需要重传,并且次数减1

        if(weakSelf.needRestart&& weakSelf.reUploadCount>0) {

            weakSelf.reUploadCount--;

            [weakSelfstartUpload];

        }else{

            if(weakSelf.handler) {

                weakSelf.handler(weakSelf.uploadDic.allValues);

            }

        }

    });

}

- (void)updateMode:(UploadFileModel*)mode state:(UploadState)state{

    [self.locklock];

    mode.state= state;

    if(state ==UploadStateFailed) {

        self.needRestart=YES;

    }

    [self.lockunlock];

}

-(NSMutableDictionary *)uploadDic{

    if(!_uploadDic) {

        _uploadDic = [NSMutableDictionary new];

    }

    return _uploadDic;

}

-(NSUInteger)maxQueueCount{

    if (_maxQueueCount == 0) {

        _maxQueueCount = 1;

    }

    return _maxQueueCount;

}

具体代码点这里

相关文章

  • iOS GCD多线程实现并发上传多个本地文件

    多线程编程是软件工程是必备的基础技能之一,对于iOS开发,多线程的技术有很多,有最原始的pthread,面向对象的...

  • 知其然亦知其所以然-NSOperation并发编程

    对于iOS的并发编程, 用的最普遍的就是GCD了, GCD结合Block可以so easy的实现多线程并发编程. ...

  • iOS开发多线程之GCD

    iOS开发多线程之GCDiOS开发之GCD同步任务加强iOS开发之GCD串行队列iOS开发之GCD并发队列 GCD...

  • iOS开发之GCD并发队列

    iOS开发多线程之GCDiOS开发之GCD同步任务加强iOS开发之GCD串行队列iOS开发之GCD并发队列 03 ...

  • iOS开发之GCD同步任务加强

    iOS开发多线程之GCDiOS开发之GCD同步任务加强iOS开发之GCD串行队列iOS开发之GCD并发队列 004...

  • iOS多线程之Operation Queues

    iOS中常见的实现多线程并发的有三种方式,NSThread,NSOperation和GCD。Operation Q...

  • iOS开发之GCD串行队列

    iOS开发多线程之GCDiOS开发之GCD同步任务加强iOS开发之GCD串行队列iOS开发之GCD并发队列 实例d...

  • GCD 的使用一些常用方法

    可以参考类似文章:iOS使用dispatch_group实现分组并发网络请求 GCD是iOS中的一种多线程技术,全...

  • GCD练习

    GCD练习 ios 多线程 GCD : ios 多线程 全剧队列,异步执行 线程间通信 信号量 文件锁 单利模式 ...

  • iOS 多线程

    参考链接 iOS多线程iOS 多线程:『GCD』详尽总结iOS简单优雅的实现复杂情况下的串行需求(各种锁、GCD ...

网友评论

    本文标题:iOS GCD多线程实现并发上传多个本地文件

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