项目介绍:
MCDownloadManager
https://github.com/agelessman/MCDownloadManager
我们用AFNetworking小试牛刀,写一个简单的下载器来演示功能。DEMO直接下载:
前言为什么AFNetworking能够成为顶级框架?我们究竟该如何领悟它的精髓所在?这都是很难的问题。安全,高效,流畅,这3个特性缺一不可。假如我们要封装一个通用的网络框架,提供一个文件下载器是很有必要的。按照 管理编程原则 ,这个下载管理器应该管理所有的下载任务和依据。
这是一个简单的下载器,只为了功能演示
下载器提供的功能
- 根据一个url下载文件 我们下载一个文件,最重要的就是url,因此我们应该把这个url作为下载的唯一标识。
- 提供下载进度 为了增加用户体验,往往在下载文件的同时,展示一个下载进度告诉用户当前的下载情况,有的人喜欢使用bytesWriten/totalBytesWriten/totalExpectedBytesWriten,但AFNetworking中使用的都是NSProgress。因此,我们也采用NSProgress表示进度。
- 下载完成的回调 通知下载完成的方式有通知/代理/Block,我们采用的是Block。
- 下载失败的回调 同上
- 根据url获取下载对象 我们把下载的对象包装成了MCDownloadReceipt,我能够在MCDownloadReceipt对象中获取到我们需要的所有内容。
- 回复/暂停/取消 下载任务 这些功能,我们使用协议来实现。
- 下载限制和顺序 我们能够自定义同时下载文件的个数,默认为4个。能够自定义等待队列中的任务是先进先出还是后进先出。
设计思路
写一个下载器,一定需要一个对象来描述下载的文件。在这个下载器中,我们使用MCDownloadReceipt。既然是一个信息的载体,那么从设计角度来说,我们应该使用它来存储跟文件相关的内容,不应该让他完成其他更多的事情,比如说开始,暂停等等。
MCDownloadReceipt使用归档进行本地化存储。
核心下载使用NSURLSession实现,下边我们会介绍详情。
MCDownloadReceiptMCDownloadReceipt的主要功能是用于记录下载信息。即使下载未完成,也能在MCDownloadReceipt的filePath路径下找个这个文件。
我们先来看看暴露出来的头文件信息:
- NSString *url 作为MCDownloadReceipt的唯一标识。
- NSString *filePath MCDownloadReceipt的文件索引。
- NSString *filename MCDownloadReceipt的文件名,命名规则为:把url进行MD5编码后作为文件名,url中如果有后缀,就拼接后缀。
- MCDownloadState state MCDownloadReceipt的状态
- MCDownloadStateNone,
- MCDownloadStateWillResume,
- MCDownloadStateDownloading,
- MCDownloadStateSuspened,
- MCDownloadStateCompleted,
- MCDownloadStateFailed
- long long totalBytesWritten 总共写入的数据的大小
- totalBytesExpectedToWrite 文件总大小
- NSOutputStream *stream 用于把数据写入到路径中
使用方法
[Objective-C] 查看源文件 复制代码
- (void)download { [[MCDownloadManager defaultInstance] downloadFileWithURL:self.url progress:^(NSProgress * _Nonnull downloadProgress, MCDownloadReceipt *receipt) { if ([receipt.url isEqualToString:self.url]) { self.progressView.progress = downloadProgress.fractionCompleted ; } } destination:nil success:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSURL * _Nonnull filePath) { [self.button setTitle:@"播放" forState:UIControlStateNormal]; } failure:^(NSURLRequest * _Nonnull request, NSHTTPURLResponse * _Nullable response, NSError * _Nonnull error) { [self.button setTitle:@"重新下载" forState:UIControlStateNormal]; }]; }