標籤:
#import "ViewController.h"#define FileName @"121212.mp4"@interface ViewController ()<NSURLSessionDataDelegate>@property (weak, nonatomic) IBOutlet UIProgressView *proessView;/** 接受響應體資訊 */@property (nonatomic, strong) NSFileHandle *handle;@property (nonatomic, assign) NSInteger totalSize;@property (nonatomic, assign) NSInteger currentSize;@property (nonatomic, strong) NSString *fullPath;@property (nonatomic, strong) NSURLSessionDataTask *dataTask;@property (nonatomic, strong) NSURLSession *session;@end@implementation ViewController-(void)viewDidLoad{ [super viewDidLoad]; //1.讀取儲存的檔案總大小的資料,0 //2.獲得當前已經下載的資料的大小 //3.計算得到進度資訊 }-(NSString *)fullPath{ if (_fullPath == nil) { //獲得檔案全路徑 _fullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:FileName]; } return _fullPath;}-(NSURLSession *)session{ if (_session == nil) { //3.建立會話對象,設定代理 /* 第一個參數:配置資訊 [NSURLSessionConfiguration defaultSessionConfiguration] 第二個參數:代理 第三個參數:設定代理方法在哪個線程中調用 */ _session = [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] delegate:self delegateQueue:[NSOperationQueue mainQueue]]; } return _session;}-(NSURLSessionDataTask *)dataTask{ if (_dataTask == nil) { //1.url NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"]; //2.建立請求對象 NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url]; //3 佈建要求頭資訊,告訴伺服器請求那一部分資料 self.currentSize = [self getFileSize]; NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentSize]; [request setValue:range forHTTPHeaderField:@"Range"]; //4.建立Task _dataTask = [self.session dataTaskWithRequest:request]; } return _dataTask;}-(NSInteger)getFileSize{ //獲得指定檔案路徑對應檔案的資料大小 NSDictionary *fileInfoDict = [[NSFileManager defaultManager]attributesOfItemAtPath:self.fullPath error:nil]; NSLog(@"%@",fileInfoDict); NSInteger currentSize = [fileInfoDict[@"NSFileSize"] integerValue]; return currentSize;}- (IBAction)startBtnClick:(id)sender{ [self.dataTask resume];}- (IBAction)suspendBtnClick:(id)sender{ NSLog(@"_________________________suspend"); [self.dataTask suspend];}//注意:dataTask的取消是不可以恢複的- (IBAction)cancelBtnClick:(id)sender{ NSLog(@"_________________________cancel"); [self.dataTask cancel]; self.dataTask = nil;}- (IBAction)goOnBtnClick:(id)sender{ NSLog(@"_________________________resume"); [self.dataTask resume];}#pragma mark ----------------------#pragma mark NSURLSessionDataDelegate/** * 1.接收到伺服器的響應 它預設會取消該請求 * * @param session 會話對象 * @param dataTask 請求任務 * @param response 回應標頭資訊 * @param completionHandler 回調 傳給系統 */-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse:(NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{ //獲得檔案的總大小 //expectedContentLength 本次請求的資料大小 self.totalSize = response.expectedContentLength + self.currentSize; if (self.currentSize == 0) { //建立空的檔案 [[NSFileManager defaultManager]createFileAtPath:self.fullPath contents:nil attributes:nil]; } //建立檔案控制代碼 self.handle = [NSFileHandle fileHandleForWritingAtPath:self.fullPath]; //移動指標 [self.handle seekToEndOfFile]; /* NSURLSessionResponseCancel = 0,取消 預設 NSURLSessionResponseAllow = 1, 接收 NSURLSessionResponseBecomeDownload = 2, 變成下載任務 NSURLSessionResponseBecomeStream 變成流 */ completionHandler(NSURLSessionResponseAllow);}/** * 接收到伺服器返回的資料 調用多次 * * @param session 會話對象 * @param dataTask 請求任務 * @param data 本次下載的資料 */-(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{ //寫入資料到檔案 [self.handle writeData:data]; //計算檔案的下載進度 self.currentSize += data.length; NSLog(@"%f",1.0 * self.currentSize / self.totalSize); self.proessView.progress = 1.0 * self.currentSize / self.totalSize;}/** * 請求結束或者是失敗的時候調用 * * @param session 會話對象 * @param dataTask 請求任務 * @param error 錯誤資訊 */-(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{ NSLog(@"%@",self.fullPath); //關閉檔案控制代碼 [self.handle closeFile]; self.handle = nil;}-(void)dealloc{ //清理工作 //finishTasksAndInvalidate [self.session invalidateAndCancel];}@end
#####6 使用NSURLSessionDataTask實現大檔案離線斷點下載(完整)
(1)關於NSOutputStream的使用
```objc
//1. 建立一個輸入資料流,資料追加到檔案的屁股上
//把資料寫入到指定的檔案地址,如果當前檔案不存在,則會自動建立
NSOutputStream *stream = [[NSOutputStream alloc]initWithURL:[NSURL fileURLWithPath:[self fullPath]] append:YES];
//2. 開啟流
[stream open];
//3. 寫入流資料
[stream write:data.bytes maxLength:data.length];
//4.當不需要的時候應該關閉流
[stream close];
```
(2)關於網路請求要求標頭的設定(可以佈建要求下載檔案的某一部分)
```objc
//1. 佈建要求對象
//1.1 建立請求路徑
NSURL *url = [NSURL URLWithString:@"http://120.25.226.186:32812/resources/videos/minion_01.mp4"];
//1.2 建立可變請求對象
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:url];
//1.3 拿到當前檔案的殘留資料大小
self.currentContentLength = [self FileSize];
//1.4 告訴伺服器從哪個地方開始下載檔案資料
NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentContentLength];
NSLog(@"%@",range);
//1.5 佈建要求頭
[request setValue:range forHTTPHeaderField:@"Range"];
```
(3)NSURLSession對象的釋放
```objc
-(void)dealloc
{
//在最後的時候應該把session釋放,以免造成記憶體泄露
// NSURLSession設定過代理後,需要在最後(比如控制器銷毀的時候)調用session的invalidateAndCancel或者resetWithCompletionHandler,才不會有記憶體泄露
// [self.session invalidateAndCancel];
[self.session resetWithCompletionHandler:^{
NSLog(@"釋放---");
}];
}
```
(4)最佳化部分
01 關於檔案下載進度的即時更新
02 方法的獨立與抽取
---
ios開發網路學習十一:NSURLSessionDataTask離線斷點下載(斷點續傳)