小文件的下載
NSData直接從URL中加載數(shù)據(jù)
系統(tǒng)提供了方法, 讓很多東西都可以直接轉(zhuǎn)換成二進制數(shù)據(jù)的類型(可以從URL加載,file加載等等,單一數(shù)據(jù),直接寫入)
// 從提供URL中下載數(shù)據(jù)
NSData *data = [NSData dataWithContentsOfURL:
[NSURL URLWithString: @"http://b.hiphotos.baidu.com/zhidao/pic/item/728da9773912b31b31187e8c8418367adab4e11b.jpg"]];
// 數(shù)據(jù)轉(zhuǎn)換成圖片
UIImage *image = [UIImage imageWithData:data ];
self.imageView.image = image;
// 將圖片數(shù)據(jù)儿普,轉(zhuǎn)換成data數(shù)據(jù)
NSData *data1 = UIImageJPEGRepresentation(image, 0);
// 將data數(shù)據(jù)背镇,進行保存
[data1 writeToFile:@"/Users/liujiaxin/Desktop/image.jpeg" atomically:YES];
NSURLConnection如果是小文件的話,直接異步請求便能得到相應(yīng)的數(shù)據(jù).
NSURL *url = [NSURL URLWithString:@"http://www.people.com.cn/mediafile/pic/20150811/19/7260132349722664171.jpg"];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 發(fā)送請求
[NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {
// 主隊列回調(diào) 賦值UI
self.imageView.image = [UIImage imageWithData:data];
}];
NSURLSession
IOS7以后不建議使用NSURLConnection進行網(wǎng)絡(luò)數(shù)據(jù)處理. [session更加靈活,將操作封裝到任務(wù)中,通過對任務(wù)的操作能夠精確的控制操作]NSURLSession, 相當于處理放在會話層執(zhí)行 (有點大一統(tǒng)的想法, 因為二維碼相關(guān)的也需要會話)
NSURLSessionTask
/**
* 步驟
* 1尘应、創(chuàng)建task(任務(wù))【任務(wù)分為:downloadTask, dataTask(uploadTask)】
* 2笋额、利用 session 創(chuàng)建 task
* 3、創(chuàng)建 session
* 4篷扩、執(zhí)行task - resume 重新執(zhí)行
*/
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/login"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
request.HTTPMethod = @"POST";
request.HTTPBody = [@"username=520it&pwd=520it" dataUsingEncoding:NSUTF8StringEncoding];
NSURLSession *session = [NSURLSession sharedSession];
// 可以不必創(chuàng)建請求直接用url進行獲取兄猩,但是只能應(yīng)用于get請求
NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
NSLog(@"%@",[[NSString alloc]initWithData:data encoding:NSUTF8StringEncoding]);
}];
[task resume];
NSURLSessionDownloadTask
NSURLSession *session = [NSURLSession sharedSession];
/**
* 創(chuàng)建下載任務(wù) (該任務(wù)啟動后便會自己進行下載,并存儲的)
*
* @param NSURL 下載那個url 的任務(wù)
*
* @block 中的數(shù)據(jù) location下載好的文件放在磁盤的位置(會自己創(chuàng)建一個臨時文件夾的臨時目錄)
* 臨時目錄存放文件鉴未,會不定時的刪除枢冤, 所以最后將文件轉(zhuǎn)移到Cache中
* 響應(yīng)頭
*/
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_02.png"];
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url completionHandler:^(NSURL *location, NSURLResponse *response, NSError *error) {
NSFileManager *mgr = [NSFileManager defaultManager];
// [mgr createFileAtPath:[response.suggestedFilename cacheDir] contents:nil attributes:nil];
// 將文件原存儲的的地址 ,轉(zhuǎn)換成新的存儲地址铜秆, (將沙盒cache地址 用url 進行轉(zhuǎn)換)淹真。
[mgr moveItemAtURL:location toURL:[NSURL fileURLWithPath:[response.suggestedFilename cacheDir]] error:nil];
NSLog(@"%@",[response.suggestedFilename cacheDir]);
}];
[task resume];
大文件下載
NSURLConnection,在網(wǎng)絡(luò)一章中已經(jīng)說明,對于文件的下載上傳管理都是交由代理來完成的.
NSURLConnection的代理方法有:NSURLConnectionDataDelegate
1.接收到響應(yīng)式調(diào)用
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response
2.接收到數(shù)據(jù)時調(diào)用
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
[會調(diào)用多次, 每次接受文件是由限制的. 所以會進行多次調(diào)用,我們需要將每次接受到的數(shù)據(jù)進行拼接]
3.連接失敗時調(diào)用
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
4.接收數(shù)據(jù)完成時調(diào)用
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
在大文件下載之前,我們還需要考慮的是,
1>數(shù)據(jù)放在應(yīng)用中,建立一個容器專門存放數(shù)據(jù),這樣調(diào)用雖然方便,但是數(shù)據(jù)存放在應(yīng)用中,必定會消耗一定的內(nèi)存,而且會消耗一定得性能.將讀取到的數(shù)據(jù),存放在沙盒文件中
2>在沙盒中建立文件,存放數(shù)據(jù).(一邊下載,一邊存放)然后將已經(jīng)保存的數(shù)據(jù)進行讀取就可以了
第一種方案:
// 建立一個容器數(shù)據(jù),用來保存下載后的數(shù)據(jù)(但由于连茧,數(shù)據(jù)一致存在于內(nèi)存核蘸,所以非常耗性能)
@property(strong,nonatomic) NSMutableData *data;
- (NSMutableData *)data
{
if (!_data) {
_data = [NSMutableData data];
}
return _data;
}
- (void)viewDidLoad {
[super viewDidLoad];
NSString *urlStr = [ @"http://120.25.226.186:32812" stringByAppendingPathComponent: @"resources/videos/minion_01.mp4"];
NSURL *url = [NSURL URLWithString:urlStr];
// 設(shè)置請求
NSURLRequest *request = [NSURLRequest requestWithURL:url];
// 設(shè)置URLConnection,并且設(shè)置代理
NSURLConnection *urlCon = [NSURLConnection connectionWithRequest:request delegate:self];
}
// 代理方法。開始接受相應(yīng)的時候調(diào)用
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response
{
// 由協(xié)議頭 取出 接收數(shù)據(jù)的總長度
self.AllLength = response.expectedContentLength;
}
// 開始接收到數(shù)據(jù)的時候調(diào)用
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 拼接數(shù)據(jù)
[self.data appendData:data];
// 取出當前文件下載長度
self.currentLength += data.length;
// 得到控件sliderView的值
self.slideView.value = 1.0 * self.currentLength / self.AllLength;
}
// 失敗時調(diào)用
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"%s",__func__);
}
// 完成時調(diào)用
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 完成時 將拼接數(shù)據(jù)保存
[self.data writeToFile:[@"minion_01.mp4" cacheDir] atomically:YES];
}
第二種方案:
沙盒建立文件,存放下載數(shù)據(jù)
- (void)viewDidLoad {
[super viewDidLoad];
NSString *urlStr = [ @"http://120.25.226.186:32812" stringByAppendingPathComponent: @"resources/videos/minion_01.mp4"];
NSURL *url = [NSURL URLWithString:urlStr];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
NSURLConnection *urlCon = [NSURLConnection connectionWithRequest:request delegate:self];
}
// 代理方法啸驯。開始接受相應(yīng)的時候調(diào)用
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response
{
// 由協(xié)議頭 取出 接收數(shù)據(jù)的總長度
self.AllLength = response.expectedContentLength;
// 只有利用manager 才能建立文件
NSFileManager *mgr = [NSFileManager defaultManager];
// 有協(xié)議頭 得到客扎,接收到文件的名稱
NSString *filePath = [response.suggestedFilename cacheDir];
NSLog(@"%@",filePath);
self.filePath = filePath;
[mgr createFileAtPath:filePath contents:NULL attributes:NULL];
}
// 開始接收到數(shù)據(jù)的時候調(diào)用
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 拼接數(shù)據(jù)
// [self.data appendData:data];
// 建立文件句柄 --- 主要用于文件數(shù)據(jù)處理
NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:self.filePath];
// 將后一個數(shù)據(jù)寫在前一個數(shù)據(jù)的后面
[handle seekToEndOfFile];
// 寫數(shù)據(jù)
[handle writeData:data];
// 取出當前文件下載長度
self.currentLength += data.length;
// 得到控件sliderView的值
self.slideView.value = 1.0 * self.currentLength / self.AllLength;
}
// 失敗時調(diào)用
- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error
{
NSLog(@"%s",__func__);
}
// 完成時調(diào)用
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
// 完成時 將拼接數(shù)據(jù)保存
// [self.data writeToFile:[@"minion_01.mp4" cacheDir] atomically:YES];
}
第三種情況:當出現(xiàn)網(wǎng)絡(luò)情況很差,或者出現(xiàn)斷網(wǎng)的情況,這樣的話,如果下載到99.9%,然后斷網(wǎng),在進行下載的話,是不是很坑呢.....
所以應(yīng)該我們需要進行斷點續(xù)傳
斷點續(xù)傳的實現(xiàn).
協(xié)議頭,我們需要傳入這么一個參數(shù)Range: 將這么一個參數(shù)設(shè)置的話, 就想到與告訴服務(wù)請,請求的數(shù)據(jù)的范圍從什么地方開始,所以我們?nèi)绻嬖V服務(wù)器范圍(文件已經(jīng)下載的大小),就可以了
- (IBAction)btnClick:(UIButton *)sender {
// 1.切換按鈕圖片
sender.selected = !sender.selected;
// 2.判斷是否是繼續(xù)下載
if (sender.selected) {
// 繼續(xù)下載
NSLog(@"繼續(xù)下載");
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_02.mp4"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 只要設(shè)置HTTP請求頭的Range屬性, 就可以實現(xiàn)從指定位置開始下載
/*
表示頭500個字節(jié):Range: bytes=0-499
表示第二個500字節(jié):Range: bytes=500-999
表示最后500個字節(jié):Range: bytes=-500
表示500字節(jié)以后的范圍:Range: bytes=500-
*/
NSString *range = [NSString stringWithFormat:@"bytes %zd-", self.currentLength];
[request setValue:range forHTTPHeaderField:@"Range"];
self.con = [NSURLConnection connectionWithRequest:request delegate:self];
}else
{
// 暫停
NSLog(@"暫停");
[self.con cancel];
}
}
// 接收到服務(wù)器的響應(yīng)
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSHTTPURLResponse *)response
{
self.totalLength = response.expectedContentLength;
// 先去文件中獲取下載進度
// 并不是每次都需要創(chuàng)建文件
// 如果已經(jīng)下載了一部分, 就繼續(xù)在上一個文件的后面添加
if (self.currentLength > 0) {
return;
}
// 創(chuàng)建容器
// 創(chuàng)建一個空的文件, 用于保存下載的數(shù)據(jù)
NSFileManager *manager = [NSFileManager defaultManager];
NSString *path = [response.suggestedFilename cacheDir];
NSLog(@"path = %@", path);
[manager createFileAtPath:path contents:nil attributes:nil];
self.path = path;
}
// 接收到服務(wù)器返回的數(shù)據(jù)
// 會調(diào)用一次或多次
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 1.創(chuàng)建一個操作文件的句柄
// NSFileHandle *handle = [NSFileHandle fileHandleForWritingAtPath:self.path];
// 設(shè)置數(shù)據(jù)寫入的位置
// 只要調(diào)用這個方法, 每次寫入數(shù)據(jù)都會寫入到上一次的后面
[self.handle seekToEndOfFile];
// 2.利用句柄往文件中寫入數(shù)據(jù)
[self.handle writeData:data];
// 3.計算當前接收到得數(shù)據(jù)的總數(shù)
self.currentLength += data.length;
// 計算下載比例
self.progressView.progress = 1.0 * self.currentLength/self.totalLength;
}
// 接收完畢
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
[self.handle closeFile];
self.handle = nil;
NSLog(@"下載完畢");
}
#pragma mark - lazy
- (NSFileHandle *)handle
{
if (!_handle) {
// 1.創(chuàng)建一個操作文件的句柄
_handle = [NSFileHandle fileHandleForWritingAtPath:self.path];
}
return _handle;
}
第四種方式 : 句柄 (太陌生), 輸出數(shù)據(jù)流進行數(shù)據(jù)的存儲(根據(jù)文件創(chuàng)建數(shù)據(jù)輸出流, 數(shù)據(jù)流,只接受byte數(shù)據(jù) )
// 設(shè)置按鈕的監(jiān)聽
- (IBAction)clickBtn:(UIButton *)sender;
// 創(chuàng)建網(wǎng)絡(luò)請求連接
@property (strong, nonatomic) NSURLConnection *con;
// 記錄接收文件的總大小
@property (assign, nonatomic) NSInteger totalLength;
// 記錄接收到的當前文件的大小
@property (assign, nonatomic) NSInteger currentLength;
// 記錄文件存儲路徑
@property (copy, nonatomic) NSString *toPath;
// 設(shè)置輸出流,用于接收數(shù)據(jù)
@property (strong, nonatomic) NSOutputStream *stream;
@end
@implementation ViewController
- (IBAction)clickBtn:(UIButton *)sender {
sender.selected = !sender.selected;
if (sender.selected) {
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_02.mp4"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 拼接請求頭
NSString *range = [NSString stringWithFormat:@"bytes %zd-", self.currentLength];
[request setValue:range forHTTPHeaderField:@"Range"];
self.con = [NSURLConnection connectionWithRequest:request delegate:self];
}else{
// 暫停連接
[self.con cancel];
}
}
// 接收到響應(yīng)
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response
{
self.totalLength = response.expectedContentLength;
// 如果有數(shù)據(jù)便不在創(chuàng)建新的文件
if (self.currentLength > 0) {
return;
}
NSFileManager *mgr = [NSFileManager defaultManager];
// suggestFilename:就是取出響應(yīng)頭中 記錄接收數(shù)據(jù)的名字(不是路徑哦)
self.toPath = [response.suggestedFilename cacheDir];
NSLog(@"%@",self.toPath);
[mgr createFileAtPath:self.toPath contents:nil attributes:nil];
}
- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data
{
// 數(shù)據(jù)流的模式,允許拼接罚斗。
self.stream = [NSOutputStream outputStreamToFileAtPath:self.toPath append:YES];
// 只有打開數(shù)據(jù)流,才能進行數(shù)據(jù)的拼接
[self.stream open];
// 數(shù)據(jù)流徙鱼,接收byte數(shù)據(jù) 長度為:最大接收數(shù)據(jù)的長度,如果不這么設(shè)置的話针姿,接收到的數(shù)據(jù)是有問題的袱吆。
[self.stream write:data.bytes maxLength:data.length];
// 設(shè)置數(shù)據(jù)長度
self.currentLength += data.length;
self.progressView.progress = (float)1.0*self.currentLength / self.totalLength;
}
- (void)connectionDidFinishLoading:(NSURLConnection *)connection
{
NSLog(@"%s",__func__);
// 必須和句柄一樣 .關(guān)閉
[self.stream close];
}
第四種:NSURLSession
NSURLSessionTask--->普通下載
/**
* 參數(shù)1、配置搓幌,一般為默認配置
* 參數(shù)2杆故、設(shè)置代理,誰成為它的代理 遵守協(xié)議[代理方法中接受數(shù)據(jù)]
* 參數(shù)3、代理回調(diào)信息 到那個隊列(線程)[一般為主隊列]
* 注意 子協(xié)議 繼承與父協(xié)議溉愁, 遵守子協(xié)議处铛, 就是遵守父協(xié)議
*/
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/images/minion_02.png"];
// 創(chuàng)建人物,用于下載數(shù)據(jù)
NSURLSessionTask *task = [session dataTaskWithURL:url];
[task resume];
代理方法對接收到的數(shù)據(jù)進行處理,遵守的協(xié)議是:NSURLSessionDataDelegate
#pragma mark - NSURLSessionDataDelegate
// 接收到響應(yīng)
/**
* 接收到響應(yīng)時調(diào)用
*
* @param session
* @param dataTask 觸發(fā)事件的任務(wù)
* @param response 響應(yīng)頭
* @param completionHandler 回調(diào)(告訴我們?nèi)绾谓邮眨ㄊ欠瘢?shù)據(jù))
* NSURLSessionResponseCancel = 0, 默認情況 為 取消 接收數(shù)據(jù)
* NSURLSessionResponseAllow = 1, 總是允許接收數(shù)據(jù)
* NSURLSessionResponseBecomeDownload = 2 成為下載時 才接收數(shù)據(jù)
*/
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler
{
//告訴系統(tǒng),我們始終接收數(shù)據(jù)
completionHandler(NSURLSessionResponseAllow);
// 創(chuàng)建文件,用來接收數(shù)據(jù)
NSFileManager *mgr = [NSFileManager defaultManager];
NSString *toPath = [response.suggestedFilename cacheDir];
self.toPath = toPath;
NSLog(@"%@",toPath);
[mgr createFileAtPath:toPath contents:nil attributes:nil];
}
// 輸出流懶加載
- (NSOutputStream *)stream
{
if (!_stream) {
_stream = [NSOutputStream outputStreamToFileAtPath:self.toPath append:YES];
}
return _stream;
}
// 接收到數(shù)據(jù)
- (void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data
{
//這里我們直接用數(shù)據(jù)輸出流來接受數(shù)據(jù). 為了避免多次創(chuàng)建輸出流,我們利用懶加載,對輸出流進行處理
// NSOutputStream *stream = [NSOutputStream outputStreamToFileAtPath:self.toPath append:YES];
//
// self.stream = stream;
// 記住要打開數(shù)據(jù)流
[self.stream open];
[self.stream write:data.bytes maxLength:data.length];
}
// 接收完成
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
// 關(guān)閉輸出流
[self.stream close];
self.stream = nil;
// 接收完成 給空間賦值饲趋。
NSData *data = [NSData dataWithContentsOfFile:self.toPath];
UIImage *image = [UIImage imageWithData:data];
self.imageView.image = image;
NSLog(@"%s",__func__);
}
NSURLSessionTask可以實現(xiàn)更為簡單的斷點下載,蘋果為我們提供了兩個方法: 1.暫停suspend,2.開始resume
, 但調(diào)用suspend時, 任務(wù)會被暫停.當調(diào)用resume是,任務(wù)會從暫停的地方再次下載. 省去了NSURLConnection中請求頭記錄傳入數(shù)據(jù)的麻煩.
在NSURLSession中提供了專門用于包裝下載任務(wù)的類NSURLSessionDownloadTask----->普通下載
// 設(shè)置session會話,專門用來處理任務(wù)的執(zhí)行
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_16.mp4"];
// 利用會話,創(chuàng)建下載任務(wù)
NSURLSessionDownloadTask *task = [session downloadTaskWithURL:url];
// 對于不是block創(chuàng)建的任務(wù),不會立即執(zhí)行, 要調(diào)用resume
[task resume];
代理方法的實現(xiàn)遵守的協(xié)議是:NSURLSessionDownloadDelegate----代理方法中會把接收完成的數(shù)據(jù),存放在臨時文件中, 我們需要將文件調(diào)出來,放在我們希望的位置location
#pragma mark - NSURLSessionDownloadDelegate
/**
* 開始寫入數(shù)據(jù)
*
* @param session
* @param downloadTask 當前下載任務(wù)
* @param bytesWritten 當前這次寫入數(shù)據(jù)的大小
* @param totalBytesWritten 已經(jīng)寫入數(shù)據(jù)的大小
* @param totalBytesExpectedToWrite 預(yù)計寫入數(shù)據(jù)的總大小
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didWriteData:(int64_t)bytesWritten totalBytesWritten:(int64_t)totalBytesWritten totalBytesExpectedToWrite:(int64_t)totalBytesExpectedToWrite
{
self.progressView.progress = (float)1.0*totalBytesWritten / totalBytesExpectedToWrite ;
}
/**
* 恢復(fù)和暫停
*
* @param session
* @param downloadTask 當前下載任務(wù)
* @param fileOffset 恢復(fù)之后又從文件的什么地方開始進行寫入
* @param expectedTotalBytes 文件剩余總大小
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didResumeAtOffset:(int64_t)fileOffset expectedTotalBytes:(int64_t)expectedTotalBytes
{
NSLog(@"%s",__func__);
}
/**
* 下載完成時
*
* @param session
* @param downloadTask 當前下載任務(wù) (屬性中有響應(yīng)頭)
* @param location 下載的位置
*/
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTask didFinishDownloadingToURL:(NSURL *)location
{
NSURLResponse *response = downloadTask.response;
NSString *toPath = [response.suggestedFilename cacheDir];
NSLog(@"%@",toPath);
NSFileManager *mgr = [NSFileManager defaultManager];
// 將保存的臨時文件,轉(zhuǎn)移到撤蟆,指定目錄
[mgr moveItemAtURL:location toURL:[NSURL fileURLWithPath:toPath] error:nil];
}
// 完成任務(wù)
- (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error
{
NSLog(@"%s",__func__);
}
NSURLSessionDownLoadTask--->斷點下載的應(yīng)用
NSURLSessionDownloadTask 為我們提供了新的斷點下載的方法: cancelByProducingResumeData:void(^)(NSData *resumeData)
用于取消任務(wù)時,保存復(fù)原的數(shù)據(jù),并記錄當重新啟動任務(wù)時,需要從何處繼續(xù)加載 ---- 主要是用于暫停時數(shù)據(jù)的保留
dowmloadTaskWithResumeData:
必須在調(diào)用 resume
才能開始任務(wù)
恢復(fù)下載時調(diào)用, 并且重新啟動下載任務(wù)時 , 下載任務(wù)的起點已經(jīng)發(fā)生了變化, 由傳入的數(shù)據(jù) 開始啟動任務(wù)---用于啟動時,設(shè)置數(shù)據(jù)開始下載的起點
對于斷點下載的優(yōu)化------>對于每次啟動程序, 我們并不需要重新下載, 只需要在本地沙盒中存儲的數(shù)據(jù)--->繼續(xù)下載就可以了
- 需要完成的就是, 發(fā)送請求的時候, 先讀取本地數(shù)據(jù), 并計算本地數(shù)據(jù)的大小, 然后在請求頭設(shè)置時,加入請求數(shù)據(jù)開始范圍
// 設(shè)置會話,并設(shè)置會話的代理, 以及回調(diào)隊列
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_16.mp4"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
// 通過本地文件得到奕塑,下載了多少數(shù)據(jù)。 一旦重新啟動任務(wù)家肯,會從多少數(shù)據(jù)開始龄砰。 但是一旦重啟,數(shù)據(jù)的響應(yīng)頭 中期望數(shù)據(jù)長度讨衣,將會改變换棚,改變量為已將下好的長度,與總長度只差
self.fileSize = [self fileSizeWith:Name];
NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.fileSize];
// 設(shè)置請求頭內(nèi)容
[request setValue:range forHTTPHeaderField:@"Range"];
// 創(chuàng)建下載
NSURLSessionDataTask *task = [session dataTaskWithRequest:request];
self.task = task;
[self.task resume];
2.創(chuàng)建方法,專門用于計算文件內(nèi)容的大小
// 根據(jù)傳入的文件名,來計算文件的大小
- (NSInteger)fileSizeWith:(NSString *)str;
{
NSFileManager *mgr = [NSFileManager defaultManager];
NSString *toPath = [str cacheDir];
// 文件中的相關(guān)參數(shù)
NSDictionary *dict = [mgr attributesOfItemAtPath:toPath error:nil];
return [dict[NSFileSize] integerValue];
}
對于多次啟動相同下載任務(wù)的優(yōu)化(懶加載任務(wù))
#define Name @"minion_16.mp4"
@implementation ViewController
- (NSURLSessionDataTask *)task
{
if (!_task) {
NSURLSession *session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]];
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_16.mp4"];
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
self.fileSize = [self fileSizeWith:Name];
NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.fileSize];
[request setValue:range forHTTPHeaderField:@"Range"];
NSURLSessionDataTask *task = [session dataTaskWithRequest:request];
self.task = task;
}
return _task;
}
Tools 工具類:
為了能更方便的進行下載內(nèi)容存儲,所以我們給下載文件到沙盒路徑提供更為簡單的方法, 外界調(diào)用最方便的方法.
對NSString添加分類,創(chuàng)建實現(xiàn)方法
// 傳入字符串,直接在沙盒Cache中生成路徑
- (instancetype)cacheDir
{
NSString *cache = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES).firstObject;
return [cache stringByAppendingPathComponent:[self lastPathComponent]];
}
// 傳入字符串,直接在沙盒Document中生成路徑
- (instancetype)docDir
{
NSString *doc = NSSearchPathForDirectoriesInDomains(NSDocumentationDirectory, NSUserDomainMask, YES).firstObject;
return [doc stringByAppendingPathComponent:[self lastPathComponent]];
}
// 傳入字符串,直接在沙盒Temp中生成路徑
- (instancetype)temDir
{
NSString *tem = NSTemporaryDirectory();
return [tem stringByAppendingPathComponent:[self lastPathComponent]];
}