最近用到了下载,网上也搜寻过下载方面的东西,没有找到太合适的关于AFNetWorking 3.x方面的断点续传的介绍或者demo,因而本身写吧。 AFURLSessionManager这个封装了上传、下载方面的相关内容,仔细阅读不难发现,这个就是对 NSURLSession 、NSURLSessionTask 进行的封装,下载、上传这些操做用到的就是NSURLSessionTask相关子类。 先说说第一种方式,就是最简单的下载,用到的方法显而易见git
/** 第一种方式 */ //方法包含了下载所需的 参数 回调 很全面, 这里返回一个NSURLSessionDownloadTask对象,用于调用系统的方法: resume开始、继续下载,suspend暂停下载,cancel取消下载 - (NSURLSessionDownloadTask *)downloadTaskWithRequest:(NSURLRequest *)request progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler; /** 第二种方式 能够实现一种不同的断点续传 我我的感受这种方式怪怪的 并且彷佛不能作到关闭app后恢复断点续传,虽然能够保存以前下载的数据,可是下次的请求体就不存在了。 */ //首先用第一种方法进行开始下载 而后后续暂停操做 //实现断点的关键地方 用这个方法进行取消操做 能够获得resumeData - (void)cancelByProducingResumeData:(void (^)(NSData * _Nullable resumeData))completionHandler; //而后调用的方法同系统方法 /*系统方法 解释 Creates a download task with the resume data. If the download cannot be successfully resumed, URLSession:task:didCompleteWithError: will be called. */ - (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData; /*AFN方法 继续进行下载*/ - (NSURLSessionDownloadTask *)downloadTaskWithResumeData:(NSData *)resumeData progress:(nullable void (^)(NSProgress *downloadProgress))downloadProgressBlock destination:(nullable NSURL * (^)(NSURL *targetPath, NSURLResponse *response))destination completionHandler:(nullable void (^)(NSURLResponse *response, NSURL * _Nullable filePath, NSError * _Nullable error))completionHandler; //上面这种方法 按照解释就是不能正常暂停,采用的一种特殊手段暂停下载,而后进行恢复下载,理论上说就是一种日常的下载,为了处理比较特殊的状况。至于更好的用法,我暂时尚未发现。 /** 第三种方式 本文要写的重点啦 这个方法其实就是代替了系统提供的代理方法进行下载各方面的操做 详情写在下面 */ //获取文件大小 //文件大小 - (unsigned long long)fileSizeForPath:(NSString *)path { unsigned long long fileSize = 0; NSFileManager *fileManager = [NSFileManager defaultManager]; if ([fileManager fileExistsAtPath:path]) { NSError * error = nil; NSDictionary * fileDict = [fileManager attributesOfItemAtPath:path error:&error]; if (!error && fileDict) { fileSize =[fileDict fileSize]; } } return fileSize; } //建立下载请求管理对象 AFURLSessionManager * manager = [[AFURLSessionManager alloc] initWithSessionConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration]]; //建立流 NSOutputStream *outputStream = [[NSOutputStream alloc] initWithURL:[NSURL fileURLWithPath:@"文件路径"] append:YES]; //请求体 NSMutableURLRequest * request = [[NSMutableURLRequest alloc] initWithURL:[[NSURL alloc] initWithString:info.url]]; unsigned long long cacheFileSize = 0; cacheFileSize = [self fileSizeForPath:@"文件路径"]; if (cacheFileSize) { NSString *range = [NSString stringWithFormat:@"bytes=%lld-", cacheFileSize]; [request setValue:range forHTTPHeaderField:@"Range"]; } //下载对象 NSURLSessionDataTask * task = [manager dataTaskWithRequest:request completionHandler:nil]; //下载接受数据 [manager setDataTaskDidReceiveResponseBlock:^NSURLSessionResponseDisposition(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSURLResponse * _Nonnull response) { //下载文件的总大小 response.expectedContentLength + cacheFileSize //打开流 [outputStream open]; return NSURLSessionResponseAllow; }]; //写入数据 [manager setDataTaskDidReceiveDataBlock:^(NSURLSession * _Nonnull session, NSURLSessionDataTask * _Nonnull dataTask, NSData * _Nonnull data) { NSInteger result = [outputStream write:data.bytes maxLength:data.length]; if (result == -1) { //错误 outputStream.streamError; [task cancel]; } else { //正确操做 } }]; //下载完成 [manager setTaskDidCompleteBlock:^(NSURLSession * _Nonnull session, NSURLSessionTask * _Nonnull task, NSError * _Nullable error) { [outputStream close]; outputStream = nil; task = nil; if (error) { } }]; //⚠️ 上面的方法其实就是至关于系统的代理方法,具体的能够去查看 AFURLSessionManager.h 里面有详细的说明 demo待我整理整理 github奉上。