iOS中实现文件下载的简单思路(简单的组件设计)

iOS的文件下载,涉及到很深的多线程的管理,本文设计的下载逻辑,在多线程方面没有进行细致的管理,以后会完善。

前言

  • 既然是以组件的思路去设计这个功能,首先提供给外界的方法一定要是易用的,我这里是定义了两个类,AWYDownloadHelper(负责下载功能的实现),AWYDownloadManager(负责管理下载的helper),还有二个工具类,分别是文件操作,MD5加密(NSString的分类,负责把NSString对象转成MD5的String)。

  • 下载地址

  • 事件传递可以选择的方式有很多种,本文选择了block的方式。

整体流程

iOS中实现文件下载的简单思路(简单的组件设计)_第1张图片
整体流程
  1. 下载文件在整体的层面上,分为下载完成,和下载中的文件。这里通过在文件是否放在cache或者temp中来区分下载完成和未完成。
#define cachePath NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject
#define tempPath NSTemporaryDirectory()
self.fileCachePath = [cachePath stringByAppendingPathComponent:url.lastPathComponent];
self.fileTempPath = [tempPath stringByAppendingPathComponent:url.absoluteString];
  1. 下载的核心代码:
-(void)downloadWithURL:(NSURL *)url{
//    [self timer];
    
    //建立两个文件夹,temp存到一个文件夹,full存到一个文件夹
    self.fileCachePath = [cachePath stringByAppendingPathComponent:url.lastPathComponent];
    self.fileTempPath = [tempPath stringByAppendingPathComponent:[url.absoluteString MD5String]];
    //1 首先判断本地是否已经下载好,有的话直接return
    if ([AWYDownloadFileManager isFileExist:self.fileCachePath]) {
        self.state = downLoadStateCompleteSuccess;
        return;
        
    }
    if (self.task && [self.task.originalRequest.URL isEqual:url]) {
        [self resumeTask];
    }
    //2 本地没有下载完成,查看临时下载大小,在代理方法中进行比较,这么做的原因是避免了多次发送请求,这里只要拿到header信息就可以。
    _tempFileSize = [AWYDownloadFileManager fileSize:self.fileTempPath];
    
    [self downloadWithURL:url offset:_tempFileSize];
    //3 设置session的代理,分别实现两个方法,第一次收到请求返回(可以得到header去查看里边的range或者content) 下载随时返回的方法。
    
}
-(void)downloadWithURL:(NSURL *)url offset:(long long)fileSize{
    NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
    [request setValue:[NSString stringWithFormat:@"bytes=%lld-",fileSize] forHTTPHeaderField:@"Range"];
    NSURLSessionDataTask *task = [self.session dataTaskWithRequest:request];
    self.task = task;
    [self resumeTask];
    
}

//提供给manager使用的带有block参数的方法。
-(void)downloadWithURL:(NSURL *)url downInfo:(downLoadInfo)info downloadState:(downLoadStateChange)change progress:(downLoadProgressChange)progress success:(downLoadSuccess)success error:(downLoadFailed)failed{
    self.downLoadInfo = info;
    self.stateChange = change;
    self.progressChange = progress;
    self.downLoadSuccess = success;
    self.downloadFailed = failed;
    
    [self downloadWithURL:url];
    
    
}
//NSURLSesiion的代理方法,这里涉及到下载文件的读写,用到的是NSOutputStream。
- (void)URLSession:(NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask didReceiveResponse:(nonnull NSURLResponse *)response completionHandler:(nonnull void (^)(NSURLSessionResponseDisposition))completionHandler{
    NSHTTPURLResponse *hResponse = (NSHTTPURLResponse *)response;
    _totalFileSize = [hResponse.allHeaderFields[@"Content-Length"] longLongValue];
    if (hResponse.allHeaderFields[@"Content-Range"]) {
        _totalFileSize = [[hResponse.allHeaderFields[@"Content-Range"] componentsSeparatedByString:@"/"].lastObject longLongValue];
    }
    if (self.downLoadInfo) {
        self.downLoadInfo(_totalFileSize);
    }
    if (_tempFileSize > _totalFileSize) {
        [AWYDownloadFileManager removeFile:self.fileTempPath];
        completionHandler(NSURLSessionResponseCancel);
        [self downloadWithURL:response.URL offset:0];
        self.state = downLoadStateCompleteFailure;
        return;
    }
    if (_tempFileSize == _totalFileSize) {
        [AWYDownloadFileManager moveFile:self.fileTempPath toNewPath:self.fileCachePath];
        completionHandler(NSURLSessionResponseCancel);
        self.state = downLoadStateCompleteSuccess;
        return;
    }
    self.stream = [NSOutputStream outputStreamToFileAtPath:self.fileTempPath append:YES];
    [self.stream open];
        completionHandler(NSURLSessionResponseAllow);
    
}
-(void)URLSession:(NSURLSession *)session dataTask:(nonnull NSURLSessionDataTask *)dataTask didReceiveData:(nonnull NSData *)data{
    _tempFileSize += data.length;
    self.progress = _tempFileSize/_totalFileSize * 1.0;
    if (self.progressChange) {
        self.progressChange(_progress);
    }
    
    [self.stream write:data.bytes maxLength:data.length];
}

- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task
    didCompleteWithError:(nullable NSError *)error{
    if (error) {
        if (error.code == -999) {
            self.state = downLoadStatePause;
        }else{
            self.state = downLoadStateCompleteFailure;
            if (self.downloadFailed) {
                self.downloadFailed();
            }
        }
    }else{
        self.state = downLoadStateCompleteSuccess;
        [AWYDownloadFileManager moveFile:_fileTempPath toNewPath:_fileCachePath];
    }
}


你可能感兴趣的:(iOS中实现文件下载的简单思路(简单的组件设计))