文件的下载分为NSURLConnection与NSURLSession两种,前一种有恨悠久的历史了。使用相对麻烦,后者是新出来的,增加了一些额外的功能。
一、NSURLConnection实现下载
TIPS:
1、 当 NSURLConnection 下载时 , 得到的 NSData 写入文件 时 , data 并没有 占用多大内存 . ( 即使文件很大 )
2、 一点点在传 . 做的是磁盘缓存 . 而不是内存缓存机制。
3、了解在
NSURLConnection
上加代理。
[con
setDelegateQueue
:[[NSOperationQueue
alloc]
init]]
4、 NSURLResponse 记录的了 url, mineType, exceptedContentLength, suggestedFileName 等属性 . 下载时用得着 .
以下程序实现追踪下载百分比的下载(URLConnection自带的方法):
1. #import "XNDownload.h"
2.
3. typedef void(^ProgressBlock)(float percent);
4.
5. @interface XNDownload() <NSURLConnectionDataDelegate>
6.
7. @property (nonatomic, strong) NSMutableData *dataM;
8.
9. // 保存在沙盒中的文件路径
10. @property (nonatomic, strong) NSString *cachePath;
11. // 文件总长度
12. @property (nonatomic, assign) long long fileLength;
13. // 当前下载的文件长度
14. @property (nonatomic, assign) long long currentLength;
15.
16. // 回调块代码
17. @property (nonatomic, copy) ProgressBlock progress;
18.
19. @end
20.
21. @implementation XNDownload
22.
23. - (NSMutableData *)dataM
24. {
25. if (!_dataM) {
26. data];
27. }
28. return _dataM;
29. }
30.
31. - (void)downloadWithURL:(NSURL *)url progress:(void (^)(float))progress
32. {
33. // 0. 记录块代码
34. self.progress = progress;
35.
36. // 1. request GET
37. NSURLRequest *request = [NSURLRequest requestWithURL:url];
38.
39. // 2. connection
40. NSURLConnection *connection = [NSURLConnection connectionWithRequest:request delegate:self];
41.
42. // 让connection支持多线程,指定代理的工作队列即可
43. // NSURLConnection在运行时,运行循环不负责监听代理的具体执行
44. setDelegateQueue:[[NSOperationQueue alloc] init]];
45.
46. // 3. 启动连接
47. start];
48. }
49.
50. #pragma mark - 代理方法
51. // 1. 接收到服务器的响应,服务器执行完请求,向客户端回传数据
52. - (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
53. {
54. @"%@ %lld", response.suggestedFilename, response.expectedContentLength);
55. // 1. 保存的缓存路径
56. NSString *cachePath = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject];
57. self.cachePath = [cachePath stringByAppendingPathComponent:response.suggestedFilename];
58. // 2. 文件总长度
59. self.fileLength = response.expectedContentLength;
60. // 3. 当前下载的文件长度
61. self.currentLength = 0;
62.
63. // 清空数据
64. self.dataM setData:nil];
65. }
66.
67. // 2. 接收数据,从服务器接收到数据
68. - (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
69. {
70. // 拼接数据
71. self.dataM appendData:data];
72.
73. // 根据data的长度增加当前下载的文件长度
74. self.currentLength += data.length;
75.
76. float progress = (float)self.currentLength / self.fileLength;
77.
78. // 判断是否定义了块代码
79. if (self.progress) {
80. mainQueue] addOperationWithBlock:^{
81. // 强制运行循环执行一次更新
82. currentRunLoop] runMode:NSDefaultRunLoopMode beforeDate:[NSDate date]];
83.
84. self.progress(progress);
85. }];
86. }
87. }
88.
89. // 3. 完成接收
90. - (void)connectionDidFinishLoading:(NSURLConnection *)connection
91. {
92. @"%s %@", __func__, [NSThread currentThread]);
93. // 将dataM写入沙盒的缓存目录
94. // 写入数据,NSURLConnection底层实现是用磁盘做的缓存
95. self.dataM writeToFile:self.cachePath atomically:YES];
96. }
97.
98. // 4. 出现错误
99. - (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
100. {
101. @"%@", error.localizedDescription);
102. }
103.
104. @end
二、NSURLSession实现下载
NSURLSession能实现断点续传,暂停下载等功能。
1、session提供的是 开了多个线程的异步下载.
2、下载的暂停与 续传: (session的 代理中的方法)
*弄一个NSData变量来保存下载东西.暂停时将下载任务task清空.
* 续传:将暂停时的data交给session继续下载,并将先前的data清空.
3、 task 一定要 resume 才开始执行 .
1. #import "XNViewController.h"
2.
3. @interface XNViewController () <NSURLSessionDownloadDelegate>
4.
5. // 下载网络回话
6. @property (nonatomic, strong) NSURLSession *session;
7. // 下载任务
8. @property (nonatomic, strong) NSURLSessionDownloadTask *downloadTask;
9. // 续传的二进制数据
10. @property (nonatomic, strong) NSData *resumeData;
11. @end
12.
13. @implementation XNViewController
14.
15. - (NSURLSession *)session
16. {
17. if (!_session) {
18. NSURLSessionConfiguration *config = [NSURLSessionConfiguration defaultSessionConfiguration];
19. sessionWithConfiguration:config delegate:self delegateQueue:nil];
20. }
21. return _session;
22. }
23.
24. - (void)viewDidLoad
25. {
26. super viewDidLoad];
27.
28. self downloadFile];
29. }
30.
31. // 暂停下载任务
32. - (IBAction)pause
33. {
34. // 如果下载任务不存在,直接返回
35. if (self.downloadTask == nil) return;
36.
37. // 暂停任务(块代码中的resumeData就是当前正在下载的二进制数据)
38. // 停止下载任务时,需要保存数据
39. self.downloadTask cancelByProducingResumeData:^(NSData *resumeData) {
40. self.resumeData = resumeData;
41.
42. // 清空并且释放当前的下载任务
43. self.downloadTask = nil;
44. }];
45. }
46.
47. - (IBAction)resume
48. {
49. // 要续传的数据是否存在?
50. if (self.resumeData == nil) return;
51.
52. // 建立续传的下载任务
53. self.downloadTask = [self.session downloadTaskWithResumeData:self.resumeData];
54. self.downloadTask resume];
55.
56. // 将此前记录的续传数据清空
57. self.resumeData = nil;
58. }
59.
60. // 如果在开发中使用到缓存目录,一定要提供一个功能,“清除缓存”!
61. /** 下载文件 */
62. - (void)downloadFile
63. {
64. NSString *urlStr = @"http://localhost/苍老师全集.rmvb";
65. stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding];
66.
67. NSURL *url = [NSURL URLWithString:urlStr];
68.
69. // (1) 代理 & 直接启动任
70. // 2. 启动下载任务
71. self.downloadTask = [self.session downloadTaskWithURL:url];
72.
73. self.downloadTask resume];
74. }
75.
76. #pragma mark - 下载代理方法
77. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
78. {
79. @"完成 %@ %@", location, [NSThread currentThread]);
80. }
81.
82. /**
83. bytesWritten : 本次下载的字节数
84. totalBytesWritten : 已经下载的字节数
85. totalBytesExpectedToWrite : 下载总大小
86. */
87. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
88. {
89. float progress = (float)totalBytesWritten / totalBytesExpectedToWrite;
90.
91. mainQueue] addOperationWithBlock:^{
92. //主线程中更新进度UI操作。。。。
93. }];
94. }
95.
96. /** 续传的代理方法 */
97. - (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
98. {
99. @"offset : %lld", fileOffset);
100. }
101.
102. @end