iOS開發之網路編程--4、NSURLSessionDataTask實現檔案下載(離線斷點續傳下載) <進度值顯示最佳化>,nsurlsession斷點續傳

來源:互聯網
上載者:User

iOS開發之網路編程--4、NSURLSessionDataTask實現檔案下載(離線斷點續傳下載) <進度值顯示最佳化>,nsurlsession斷點續傳

前言:根據前篇《iOS開發之網路編程--2、NSURLSessionDownloadTask檔案下載》或者《iOS開發之網路編程--3、NSURLSessionDataTask實現檔案下載(離線斷點續傳下載)》,都遺留了一個細節未處理的問題,那就是在離線斷點下載的過程中,當應用程式重新啟動之後,進度條的進度值預設沒有設定為之前已經下載的進度,根據基本公式"當前進度值 = 已經下載的資料長度 ÷ 最終下載完的資料總長度",已經下載的資料長度可以由沙箱中已經下載的那部分資料擷取,但是最終下載完的資料總長度就需要通過網路返回的資訊了,但是別忘了,每一次重新啟動應用程式初始狀態預設都是暫停下載,或者是斷網的情況下無法請求網路資料,那麼如何擷取這個"最終下載完的資料總長度"呢?

先看看效果:

問題解決:"最終下載完的資料總長度"可以在首次從0開始下載的時候通過網路擷取,然後將其"最終下載完的資料總長度"這個值儲存在緩衝中的某個檔案(這個檔案可以是字典等等)中,等待下一次擷取。

       而我則採用的方法是將這個"最終下載完的資料總長度"作為檔案的屬性添加進檔案屬性列表中,以備下一次讀取的時候,獲得到這個檔案之後,就可以讀取該檔案的屬性列表中的"最終下載完

     的資料總長度"的屬性和屬性值。

在這裡不得不先介紹一個工具類,讀者可以通過本人的另一篇博文隨筆先瞭解其功能:iOS開發 -- 為本地檔案添加自訂屬性的工具類

為本地檔案添加屬性之後,可以列印看的到:

本人花了點時間將網路下載這部分簡單的封裝成了一個工具類:DownloadTool,下面就展示源碼:

DownloadTool.h

 1 #import <Foundation/Foundation.h> 2  3  4 // 定義一個block用來傳遞進度值 5 typedef  void (^SetProgressValue)(float progressValue); 6  7 @interface DownloadTool : NSObject 8  9 /** 建立下載工具對象 */10 + (instancetype)DownloadWithURLString:(NSString*)urlString setProgressValue:(SetProgressValue)setProgressValue;11 /** 開始下載 */12 -(void)startDownload;13 /** 暫停下載 */14 -(void)suspendDownload;15 16 @end

DownloadTool.m

  1 #import "DownloadTool.h"  2   3 #import "ExpendFileAttributes.h"  4   5 #define Key_FileTotalSize @"Key_FileTotalSize"  6   7 @interface DownloadTool () <NSURLSessionDataDelegate>  8 /** Session會話 */  9 @property (nonatomic,strong)NSURLSession *session; 10 /** Task任務 */ 11 @property (nonatomic,strong)NSURLSessionDataTask *task; 12 /** 檔案的全路徑 */ 13 @property (nonatomic,strong)NSString *fileFullPath; 14 /** 傳遞進度值的block */ 15 @property (nonatomic,copy) SetProgressValue setProgressValue; 16 /** 當前已經下載的檔案的長度 */ 17 @property (nonatomic,assign)NSInteger currentFileSize; 18 /** 輸出資料流 */ 19 @property (nonatomic,strong)NSOutputStream *outputStream; 20 /** 不變的檔案總長度 */ 21 @property (nonatomic,assign)NSInteger fileTotalSize; 22 @end 23  24 @implementation DownloadTool 25  26 + (instancetype)DownloadWithURLString:(NSString*)urlString setProgressValue:(SetProgressValue)setProgressValue{ 27     DownloadTool* download = [[DownloadTool alloc] init]; 28     download.setProgressValue = setProgressValue; 29     [download getFileSizeWithURLString:urlString]; 30     [download creatDownloadSessionTaskWithURLString:urlString]; 31     NSLog(@"%@",download.fileFullPath); 32     return download; 33 } 34 // 剛建立該網路下載工具類的時候,就需要查詢本地是否有已經下載的檔案,並返回該檔案已經下載的長度 35 -(void)getFileSizeWithURLString:(NSString*)urlString{ 36     // 建立檔案管理者 37     NSFileManager* fileManager = [NSFileManager defaultManager]; 38     // 擷取檔案各個部分 39     NSArray* fileComponents = [fileManager componentsToDisplayForPath:urlString]; 40     // 擷取下載之後的檔案名稱 41     NSString* fileName = [fileComponents lastObject]; 42     // 根據檔案名稱拼接沙箱全路徑 43     NSString* fileFullPath = [[NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES) lastObject] stringByAppendingPathComponent:fileName]; 44     self.fileFullPath = fileFullPath; 45      46     NSDictionary* attributes = [fileManager attributesOfItemAtPath:fileFullPath 47                                                              error:nil]; 48     // 如果有該檔案,且為下載沒完成,就直接拿出該檔案的長度設定進度值,並設定當前的檔案長度 49     NSInteger fileCurrentSize = [attributes[@"NSFileSize"] integerValue]; 50     // 如果檔案長度為0,就不需要計算進度值了 51     if (fileCurrentSize != 0) { 52         // 擷取最終的檔案中長度 53         NSInteger fileTotalSize = [[ExpendFileAttributes stringValueWithPath:self.fileFullPath key:Key_FileTotalSize] integerValue]; 54         self.currentFileSize = fileCurrentSize; 55         self.fileTotalSize = fileTotalSize; 56         // 設定進度條的值 57         self.setProgressValue(1.0 * fileCurrentSize / fileTotalSize); 58     } 59     NSLog(@"當前檔案長度:%lf" , self.currentFileSize * 1.0); 60 } 61 #pragma mark - 建立網路請求會話和任務,並啟動任務 62 -(void)creatDownloadSessionTaskWithURLString:(NSString*)urlString{ 63     //判斷檔案是否已經下載完畢 64     if (self.currentFileSize == self.fileTotalSize && self.currentFileSize != 0) { 65         NSLog(@"檔案已經下載完畢"); 66         return; 67     } 68     NSURLSession* session = 69     [NSURLSession sessionWithConfiguration:[NSURLSessionConfiguration defaultSessionConfiguration] 70                                   delegate:self 71                              delegateQueue:[[NSOperationQueue alloc]init]]; 72     NSURL* url = [NSURL URLWithString:urlString]; 73     NSMutableURLRequest* request = [NSMutableURLRequest requestWithURL:url]; 74     //2.3 佈建要求頭 75     NSString *range = [NSString stringWithFormat:@"bytes=%zd-",self.currentFileSize]; 76     [request setValue:range forHTTPHeaderField:@"Range"]; 77     NSURLSessionDataTask* task = [session dataTaskWithRequest:request]; 78     self.session = session; 79     self.task = task; 80 } 81  82 #pragma mark - 控制下載的狀態 83 // 開始下載 84 -(void)startDownload{ 85     [self.task resume]; 86 } 87 // 暫停下載 88 -(void)suspendDownload{ 89     [self.task suspend]; 90 } 91 #pragma mark - NSURLSessionDataDelegate 的代理方法 92 // 收到響應調用的代理方法 93 -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveResponse: 94 (NSURLResponse *)response completionHandler:(void (^)(NSURLSessionResponseDisposition))completionHandler{ 95     NSLog(@"執行了收到響應調用的代理方法"); 96     // 建立輸出資料流,並開啟流 97     NSOutputStream* outputStream = [[NSOutputStream alloc] initToFileAtPath:self.fileFullPath append:YES]; 98     [outputStream open]; 99     self.outputStream = outputStream;100     // 如果當前已經下載的檔案長度等於0,那麼就需要將總長度資訊寫入檔案中101     if (self.currentFileSize == 0) {102         NSInteger totalSize = response.expectedContentLength;103         NSString* totalSizeString = [NSString stringWithFormat:@"%ld",totalSize];104         [ExpendFileAttributes extendedStringValueWithPath:self.fileFullPath key:Key_FileTotalSize value:totalSizeString];105         // 別忘了設定總長度106         self.fileTotalSize = totalSize;107     }108     // 允許收到響應109     completionHandler(NSURLSessionResponseAllow);110 }111 // 收到資料調用的代理方法112 -(void)URLSession:(NSURLSession *)session dataTask:(NSURLSessionDataTask *)dataTask didReceiveData:(NSData *)data{113     NSLog(@"執行了收到資料調用的代理方法");114     // 通過輸出資料流寫入資料115     [self.outputStream write:data.bytes maxLength:data.length];116     // 將寫入的資料的長度計算加進當前的已經下載的資料長度117     self.currentFileSize += data.length;118     // 設定進度值119     NSLog(@"當前檔案長度:%lf,總長度:%lf",self.currentFileSize * 1.0,self.fileTotalSize * 1.0);120     NSLog(@"進度值: %lf",self.currentFileSize * 1.0 / self.fileTotalSize);121     // 擷取主線程122     NSOperationQueue* mainQueue = [NSOperationQueue mainQueue];123     [mainQueue addOperationWithBlock:^{124         self.setProgressValue(self.currentFileSize * 1.0 / self.fileTotalSize);125     }];126 }127 // 資料下載完成調用的方法128 -(void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)task didCompleteWithError:(NSError *)error{129     // 關閉輸出資料流 並關閉強指標130     [self.outputStream close];131     self.outputStream = nil;132     // 關閉會話133     [self.session invalidateAndCancel];134     NSLog(@"%@",[NSThread currentThread]);135 }136 -(void)dealloc{137 }138 @end

使用樣本源碼:

 1 #import "ViewController.h" 2 #import "RainbowProgress.h" 3  4 #import "DownloadTool.h" 5  6 #define MP4_URL_String @"http://120.25.226.186:32812/resources/videos/minion_12.mp4" 7  8  9 @interface ViewController ()10 @property (weak, nonatomic) IBOutlet UILabel *showDownloadState;11 /** 彩虹進度條 */12 @property (nonatomic,weak)RainbowProgress *rainbowProgress;13 /** 網路下載工具對象 */14 @property (nonatomic,strong)DownloadTool *download;15 @end16 17 @implementation ViewController18 19 - (void)viewDidLoad {20     [super viewDidLoad];21     [self setSelfView];22     [self addProgress];23     [self addDownload];24     25 }26 // 啟動和關閉的網路下載開關27 - (IBAction)SwitchBtn:(UISwitch *)sender {28     if (sender.isOn) {29         self.showDownloadState.text = @"開始下載";30         [self.download startDownload];31     }else{32         self.showDownloadState.text = @"暫停下載";33         [self.download suspendDownload];34     }35 }36 #pragma mark - 設定控制器View37 -(void)setSelfView{38     self.view.backgroundColor = [UIColor blackColor];39 }40 #pragma mark - 添加彩虹進度條41 -(void)addProgress{42     // 建立彩虹進度條,並啟動動畫43     RainbowProgress* rainbowProgress = [[RainbowProgress alloc] init];44     [rainbowProgress startAnimating];45     [self.view addSubview:rainbowProgress];46     self.rainbowProgress = rainbowProgress;47 }48 #pragma mark - 建立網路下載任務49 -(void)addDownload{50     DownloadTool* download = [DownloadTool DownloadWithURLString:MP4_URL_String setProgressValue:^(float progressValue) {51         self.rainbowProgress.progressValue = progressValue;52     }];53     self.download = download;54 }55 56 #pragma mark - 設定狀態列樣式57 -(UIStatusBarStyle)preferredStatusBarStyle{58     return UIStatusBarStyleLightContent;59 }60 61 @end

(中間有個過程是重新啟動應用程式看看進度條顯示的效果,然後繼續測試開始下載和暫停下載):

 

百度雲分享源碼連結: http://pan.baidu.com/s/1eRwRkZo 密碼: 787n

轉載請註明出處:http://www.cnblogs.com/goodboy-heyang/p/5200873.html ,尊重勞動成果。

相關文章

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.