NSURLSessionDataTask与NSOperationQueue实现多文件断点下载(任意时刻终止进程,重启应用,自动重启下载)...
效果展示
gif有點大,直接連接:7qnbrb.com1.z0.glb.clouddn.com/download.gi…
知識要點
NSOperationQueue
-
蘋果提供的一套多線程解決方案,基于GCD更高一層的封裝,完全面向對象。
-
我們使用NSOperation配合NSOperationQueue來實現多線程,執行異步任務。
NSOperation 實現多線程的使用步驟分為三步:
1.創建操作:先將需要執行的操作封裝到一個 NSOperation 對象中。
2.創建隊列:創建 NSOperationQueue 對象。
3.將操作加入到隊列中:將 NSOperation 對象添加到 NSOperationQueue 對象中。 -
NSOperation是個抽象類,不能用來封裝操作,NSOperation的兩個子類NSInvocationOperation與NSBlockOperation以及自定義繼承自NSOperation的子類。由于我們需要根據NSURLSessionTask的狀態來控制隊列的執行,所以只能自定義NSOperation,并在子類內部通用KVO的方式來監聽NSURLSessionTask狀態
NSURLSession
NSURLSession是iOS7中用于替換NSURLConnection而新增的接口,用于網絡相關的操 作,包括數據請求,上傳,下載,處理認證等工具,能處理http協議中的所用事情。但NSURLSession并不直接工作,而是由NSURLSessionTask完成,NSURLSessionTask 有三個子類:數據請求NSURLSessionDataTask,上傳NSURLSessionUploadTask,下載NSURLSessionDownloadTask,可以使用block,delegate來進行初始化,當然使用NSURLSessionDataTask來進行上傳和下載工作也是可行的。 關系結構
NSURLSessionDataTask與NSURLSessionDownloadTask方案選擇的考慮
-
NSURLSessionDownloadTask
- 優點:使用cancelByProducingResumeData取消下載時,能獲取到當前下載文件的情況的resumeData,包含下載了多少,總大小等,以及能配置后臺下載功能。
- 缺點:NSURLSessionDownloadTask下載下來的二進制文件會先存儲在tmp臨時文件(該文件夾下的內容隨時可能清空)中,在下載結束后,才將文件移動到指定的沙盒文件中。
-
NSURLSessionDataTask
- 優點:直接將二進制數據寫入可以永久存儲的沙盒文件(NSDocumentDirectory,NSLibraryDirectory)中
- 缺點:需要自定義NSFileHandle,然后將下載的數據拼接存儲在本地
-
對比:通過兩者的優缺點對比,NSURLSessionDownloadTask如果需要實現在進程終止后,能自啟下載,就必須不斷的將tmp的二進制文件拷貝到NSDocumentDirectory或NSLibraryDirectory中,以及不斷獲取resumeData值,這樣會造成很大的資源的浪費以及內存的開銷。使用NSURLSessionDataTask避免了二進制文件的拷貝,將基礎的數據在開始下載是就存入到數據庫中,從而做到任意時刻終止進程,重啟應用,都能獲取到資源路徑,資源大小,下載的狀態,保持應用終止前的狀態或自動重啟下載。
-
基于對比,最終我選擇使用NSURLSessionDataTask來實現斷點下載。
FMDB
關于FMDB,不做更多的介紹。
思路
- 1.準備下載:將下載任務添加到下載任務隊列中,并將文件名稱,資源路徑,下載狀態(等待下載)存儲到數據庫中
- 2.開始下載:獲取到文件總大小,名稱,更新表數據:下載狀態為正在下載,并將二進制數據使用NSFileHandle寫入沙盒
- 3.暫停 > 更新表數據:當前下載了多少,下載狀態改成:暫停
- 4.取消下載 > 數據庫中刪除該條數據,從任務數組中移除該數據
- 5.下載完成 > 數據庫中刪除該條數據,從任務數組中移除該數據
- 6.應用被殺掉,重啟應用
- 6.1.檢查是否有下載隊列
- 6.2.對于處于下載狀態的隊列,自動啟動
- 6.33.處于暫停及其它情況的隊列,依然保持原本的情況
添加下載任務到隊列中
這里分兩塊:第一次新增,以及由暫停或失敗狀態重啟
- (void)addDownloadQueue:(NSString *)fileUrl {MHDownloadModel *downloadModel = [self fetchDownloadModelWithFileUrl:fileUrl];if (downloadModel) {return;}//如果數據庫中存在該文件,則表明僅僅只是由暫停或失敗狀態,重啟下載(暫停 -> 正在下載)downloadModel = [[MHFileDatabase shareInstance] queryModelWitFileName:fileUrl.lastPathComponent];if (downloadModel) {//更新下載文件的狀態[[MHFileDatabase shareInstance] updateDownloadStatusWithFileName:fileUrl.lastPathComponent downloadStatus:MHDownloadStatusDownloading];} else {//插入數據,記錄下載文件[[MHFileDatabase shareInstance] insertFileWithFileName:fileUrl.lastPathComponent filePath:fileUrl fileTotalSize:0];downloadModel = [MHDownloadModel new];downloadModel.filePath = fileUrl;}[self.downloadTasks addObject:downloadModel];[self startDownLoadWithUrl:fileUrl]; } 復制代碼啟動下載任務
此時并不一定馬上下載,下載的啟動由NSOperationQueue控制,默認最大的下載并發數為3。
- (void)startDownLoadWithUrl:(NSString *)url {MHDownloadModel *downloadModel = [self fetchDownloadModelWithFileUrl:url];downloadModel.downloadStatus = MHDownloadStatusDownloadWait;NSURLSessionDataTask *task = downloadModel.task;if (task && task.state == NSURLSessionTaskStateRunning) {return;}__weak typeof(self) weakSelf = self;MHURLSessionTaskOperation *operation = [MHURLSessionTaskOperation operationWithURLSessionTask:nil sessionBlock:^NSURLSessionTask *{__strong typeof(weakSelf) strongSelf = weakSelf;NSLog(@"thread : %@, MHCustomOperation operationWithURLSessionTask", [NSThread currentThread]);return [strongSelf downloadDataTaskWithUrl:url];}];[self.operationQueue addOperation:operation]; } 復制代碼封裝下載請求:
1.設置url
2.設置request,設置請求頭、請求體
3.發送請求
實現代理NSURLSessionDataDelegate
- 開始下載:獲取目標 文件的大小,創建沙盒文件 必須調用 completionHandler (NSURLSessionResponseAllow)
- 獲取下載進度,并將二進制數據寫入沙盒
- 下載完成或出錯
完整案例:Github
轉載于:https://juejin.im/post/5b8bb41b51882542c43a0843
總結
以上是生活随笔為你收集整理的NSURLSessionDataTask与NSOperationQueue实现多文件断点下载(任意时刻终止进程,重启应用,自动重启下载)...的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: d3dx9_34.dll是什么
- 下一篇: d3dx10_42.dll是什么