文件的下载分为NSURLConnectionNSURLSession两种,前一种有恨悠久的历史了。使用相对麻烦,后者是新出来的,增加了一些额外的功能。

一、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