標籤:
一、傳統的下載檔案的方式
- (void)downloaderWithUrl:(NSURL *)url{ NSURLRequest *request = [NSURLRequest requestWithURL:url]; [NSURLConnection sendAsynchronousRequest:request queue:[[NSOperationQueue alloc] init] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { if (!connectionError) { NSHTTPURLResponse *urlResponse = (NSHTTPURLResponse *)response; if (urlResponse.statusCode == 200 || urlResponse.statusCode == 304) { [data writeToFile:@"/Users/gxiangzi/Desktop/a.mp4" atomically:YES]; NSLog(@"OK"); } }else { NSLog(@"錯誤"); } }];}
但是這種方式存在著弊端:
1> 用不無法跟蹤下載的進度,無法直觀的顯示下載進度
2> 檔案下載的時候,都會先下載到記憶體之中,導致記憶體 > 所需檔案的大小長度,會造成程式崩潰等現象(可以查看記憶體的耗費)
二、代理的方式下載程式(NSURLConnectionDownloadDelegate)
#import "GXDownloader.h"@interface GXDownloader () <NSURLConnectionDownloadDelegate>@end@implementation GXDownloader- (void)downloaderWithUrl:(NSURL*)url{ NSURLRequest* request = [NSURLRequest requestWithURL:url]; [[NSURLConnection alloc] initWithRequest:request delegate:self];}#pragma mark - NSURLConnectionDownloadDelegate/** bytesWritten: 表示下載的資料位元組數 totalBytesWritten:總的已經下載的位元組數 expectedTotalBytes:期望的總的位元組數 */- (void)connection:(NSURLConnection*)connection didWriteData:(long long)bytesWritten totalBytesWritten:(long long)totalBytesWritten expectedTotalBytes:(long long)expectedTotalBytes{ float progress = (float)totalBytesWritten / expectedTotalBytes; NSLog(@"%f", progress);}/** * @param connection * @param totalBytesWritten : 總的已經下載的位元組數 * @param expectedTotalBytes : 期望總的位元組數 */- (void)connectionDidResumeDownloading:(NSURLConnection*)connection totalBytesWritten:(long long)totalBytesWritten expectedTotalBytes:(long long)expectedTotalBytes{}/** * @param connection * @param destinationURL:下載完的目標路徑 */- (void)connectionDidFinishDownloading:(NSURLConnection*)connection destinationURL:(NSURL*)destinationURL{ NSLog(@"%@", destinationURL);}
優點:
1> 該種方式可以追蹤檔案下載的進度;
2> 也可以解決記憶體消耗過大的問題
弊端: 這丫的 下載的檔案沒有 ,就是雖然你顯示下載完成,但是你本地找不到該檔案------沒有任何卵用
三、第三種方式--代理(NSURLConnectionDataDelegate)
//// GXDownloader.m// 02-下載//// Created by gxiangzi on 15/8/21.// Copyright (c) 2015年 hqu. All rights reserved.//#import "GXDownloader.h"@interface GXDownloader () <NSURLConnectionDataDelegate>// 檔案的總長度@property (nonatomic, assign) long long expectedContentLength;// 已經接受到檔案的長度@property (nonatomic, assign) long long receivedContentLength;// 已經已接收的檔案的總長度@property (nonatomic, strong) NSMutableData* receivedData;@end@implementation GXDownloader- (void)downloaderWithUrl:(NSURL*)url{ NSURLRequest* request = [NSURLRequest requestWithURL:url]; [[NSURLConnection alloc] initWithRequest:request delegate:self];}#pragma mark - NSURLConnectionDataDelegate/** * 已經接受到回應標頭 */- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response{ self.expectedContentLength = response.expectedContentLength;}/** * 檔案接受到一點的時候就是用 */- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data{ // 把位元據進行拼接 [self.receivedData appendData:data]; // 拼接長度 self.receivedContentLength += data.length; float progress = (float)self.receivedContentLength / self.expectedContentLength; NSLog(@"下載進度: %.2f",progress); }/** * 下載出錯的時候調用 */- (void)connection:(NSURLConnection*)connection didFailWithError:(NSError*)error{}/** * 當下載完成的時候調用 */- (void)connectionDidFinishLoading:(NSURLConnection*)connection{ NSLog(@"下載完成"); // IOS 的檔案路徑,只能講軟體操作的資料放在沙箱內 NSString *path = [NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject]; NSString *fileName = [path stringByAppendingPathComponent:@"love.mp4"]; NSLog(@"%@",fileName); [self.receivedData writeToFile:fileName atomically:YES]; }#pragma mark -懶載入- (NSMutableData*)receivedData{ if (!_receivedData) { _receivedData = [NSMutableData data]; } return _receivedData;}@end
優點:
1> 可以檢測到進度的問題
2> 檔案的寫入的路徑之中,檔案可以存在
弊端:
佔用的記憶體太大
為瞭解決上面的問題: 引入了NSHandle 和 NSOutputStream ------下一點 寫入檔案一點
四、NSHandle的使用
//// GXDownloader.m// 02-下載//// Created by gxiangzi on 15/8/21.// Copyright (c) 2015年 hqu. All rights reserved.//#import "GXDownloader.h"@interface GXDownloader () <NSURLConnectionDataDelegate>// 檔案的總長度@property (nonatomic, assign) long long expectedContentLength;// 已經接受到檔案的長度@property (nonatomic, assign) long long receivedContentLength;@end@implementation GXDownloader- (void)downloaderWithUrl:(NSURL*)url{ NSURLRequest* request = [NSURLRequest requestWithURL:url]; [[NSURLConnection alloc] initWithRequest:request delegate:self];}#pragma mark - NSURLConnectionDataDelegate/** * 已經接受到回應標頭 */- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response{ self.expectedContentLength = response.expectedContentLength;}/** * 檔案接受到一點的時候就是用 */- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data{ // 拼接長度 self.receivedContentLength += data.length; float progress = (float)self.receivedContentLength / self.expectedContentLength; NSLog(@"%f",progress); NSString* path = @"/Users/gxiangzi/Desktop/a.mp4"; NSFileHandle* handle = [NSFileHandle fileHandleForWritingAtPath:path]; // 如果handle 不會幫我們建立檔案 if (handle == nil) { [data writeToFile:path atomically:YES]; } else { //讓offset指向檔案的末尾,在末尾處追加資料 [handle seekToEndOfFile]; //寫輸入 [handle writeData:data]; //關閉 (等檔案下載完成關閉更好) [handle closeFile]; } }/** * 當下載完成的時候調用 */- (void)connectionDidFinishLoading:(NSURLConnection*)connection{ NSLog(@"下載完成");}@end
原理:下載一點資料 寫一點資料
效果:能夠達到佔用很少記憶體
五、NSOutputStream的使用
//// GXDownloader.m// 02-下載//// Created by gxiangzi on 15/8/21.// Copyright (c) 2015年 hqu. All rights reserved.//#import "GXDownloader.h"@interface GXDownloader () <NSURLConnectionDataDelegate>// 檔案的總長度@property (nonatomic, assign) long long expectedContentLength;// 已經接受到檔案的長度@property (nonatomic, assign) long long receivedContentLength;@property (nonatomic, strong) NSOutputStream* stream;@end@implementation GXDownloader- (void)downloaderWithUrl:(NSURL*)url{ NSURLRequest* request = [NSURLRequest requestWithURL:url]; [[NSURLConnection alloc] initWithRequest:request delegate:self];}#pragma mark - NSURLConnectionDataDelegate/** * 已經接受到回應標頭 */- (void)connection:(NSURLConnection*)connection didReceiveResponse:(NSURLResponse*)response{ self.expectedContentLength = response.expectedContentLength; NSString* path = @"/Users/gxiangzi/Desktop/a.mp4"; // 注意 此處的url 為本地的路徑 // 前面加 file:// 無效 // 只能使用 [NSURL fileURLWithPath:path] self.stream = [NSOutputStream outputStreamWithURL:[NSURL fileURLWithPath:path] append:YES]; [self.stream open]; }/** * 檔案接受到一點的時候就是用 */- (void)connection:(NSURLConnection*)connection didReceiveData:(NSData*)data{ // 拼接長度 self.receivedContentLength += data.length; float progress = (float)self.receivedContentLength / self.expectedContentLength; NSLog(@"%f", progress); [self.stream write:data.bytes maxLength:data.length];}/** * 當下載完成的時候調用 */- (void)connectionDidFinishLoading:(NSURLConnection*)connection{ NSLog(@"下載完成"); [self.stream close];}- (NSOutputStream *)stream{ if (_stream == nil) { _stream = [[NSOutputStream alloc] init]; } return _stream;}@end
【待整理】IOS開發之下載