在我們?nèi)粘i_(kāi)發(fā)的過(guò)程中,我們的項(xiàng)目中可能都會(huì)遇到一個(gè)需求就是去下載一個(gè)文件,然后將文件保存到本地,但是在下載的過(guò)程中一定是異步的,也就是說(shuō)我們可能會(huì)有其它的操作,這個(gè)時(shí)候可能我們的程序會(huì)遇到一些意外造成閃退的問(wèn)題亦或是用戶在下載中用戶就退出了程序,如果用戶下次進(jìn)入程序的時(shí)候就需要重新進(jìn)行下載那么一定會(huì)造成極差的用戶體驗(yàn),所以我們一定需要知道用戶下載的進(jìn)度。
最近我們的項(xiàng)目中就在做相關(guān)的問(wèn)題,官方文檔上NSUrlSessionDownloadTask章節(jié)中沒(méi)有找到我想要的方案,于是我百度了一下相關(guān)的答案,找到的一個(gè)稍微有點(diǎn)用的方案竟然是創(chuàng)建一個(gè)輪詢的timer,間隔一段時(shí)間在異步線程中將程序暫停獲取到數(shù)據(jù)后存儲(chǔ)到本地,這樣就能保證用戶最多只是小部分?jǐn)?shù)據(jù)的丟失,但是在我看來(lái)這樣的方案一定是極差的。因?yàn)槊看螘和N募霓D(zhuǎn)移都需要花費(fèi)大量的時(shí)間,然后再去resume下載任務(wù)肯定不合理。我就去嘗試了一下愛(ài)奇藝的電影的下載,我發(fā)現(xiàn)愛(ài)奇藝可以做到后臺(tái)看到的下載進(jìn)度,在后臺(tái)殺死后,再開(kāi)啟從上次進(jìn)度繼續(xù)下載,于是我就很好奇他們的實(shí)現(xiàn)方案。
當(dāng)時(shí)我想到一種方案是利用Application中- (void)applicationWillTerminate:(UIApplication*)application通知,在每次程序?qū)⒁粴⑺赖臅r(shí)候如果有正在下載的任務(wù)將之暫停然后進(jìn)行下載,為此我專門(mén)去看了對(duì)應(yīng)的官方文檔,在這個(gè)方法中我們可以做一些數(shù)據(jù)釋放和數(shù)據(jù)保存相關(guān)的操作而且有將近5秒的操作時(shí)間,其實(shí)這個(gè)時(shí)候還是一個(gè)問(wèn)題就是文檔上說(shuō)如果用戶是在后臺(tái)殺死程序的話這個(gè)方法一樣是不會(huì)被調(diào)用的,雖然有這樣的問(wèn)題,但是我還是想嘗試一下單純從前臺(tái)是不是能夠?qū)崿F(xiàn)。我起初只是寫(xiě)了一個(gè)簡(jiǎn)單的異步線程,但是發(fā)現(xiàn)內(nèi)部的打印不會(huì)執(zhí)行,所以我就用了下邊的方案進(jìn)行測(cè)試,發(fā)現(xiàn)我的打印被執(zhí)行了。我想也許我找到了一種解決方案。代碼如下

但是當(dāng)我在項(xiàng)目中加入這個(gè)通知的時(shí)候我發(fā)現(xiàn)這個(gè)時(shí)候是無(wú)法執(zhí)行到的,代碼大致如下

也許是系統(tǒng)默認(rèn)就將我的這個(gè)線程殺死不在讓我繼續(xù)去執(zhí)行了,所以顯然這樣的方案就行不通了,我后來(lái)嘗試了一些其它的方案都沒(méi)有什么效果。也漸漸的理解了在百度上為什么能夠搜到那樣的解決方案,而且Google也沒(méi)有找到很好地方案。但是在我一次次失敗的過(guò)程中,我發(fā)現(xiàn)一件好玩的事情,就是如果我們每次系統(tǒng)手動(dòng)殺死程序,下次進(jìn)入程序的時(shí)候我們都會(huì)執(zhí)行NSURLSessionTaskDelegate中的一個(gè)代理方法,代碼如下。

后續(xù)的開(kāi)發(fā)過(guò)程中我格外的關(guān)注這個(gè)方法,我發(fā)現(xiàn)無(wú)論是我們下載過(guò)程中發(fā)生錯(cuò)誤還是我們?cè)谙螺d過(guò)程中出現(xiàn)網(wǎng)絡(luò)中斷等情況都會(huì)走這個(gè)代理方法。我想也許這就是說(shuō)蘋(píng)果留個(gè)開(kāi)發(fā)者解決這一類問(wèn)題的入口,于是我打印其中的錯(cuò)誤信息大致如下

這個(gè)時(shí)候我打印一下每次暫停的時(shí)候,系統(tǒng)給我們返回的相關(guān)的數(shù)據(jù),系統(tǒng)返回?cái)?shù)據(jù)如下

通過(guò)上邊的數(shù)據(jù),我開(kāi)始有一個(gè)大膽的猜測(cè),我可以使用錯(cuò)誤中的error進(jìn)行繼續(xù)下載,然后我嘗試著用error的userinfo中的resumeData去繼續(xù)下載,發(fā)現(xiàn)這樣的方案完全能夠?qū)崿F(xiàn)我的想法。
通過(guò)上邊的嘗試,我發(fā)現(xiàn)雖然在文檔上我沒(méi)有找到斷點(diǎn)續(xù)傳如何實(shí)現(xiàn),但是其實(shí)系統(tǒng)是幫我實(shí)現(xiàn)好了的。我們?nèi)绻螺d中斷,在下一次進(jìn)入的時(shí)候,系統(tǒng)會(huì)告訴我們中斷的位置,而不需要做復(fù)雜的存儲(chǔ)過(guò)程。這樣我們就完成了一次斷點(diǎn)續(xù)傳。
為本文寫(xiě)了一個(gè)簡(jiǎn)單的demo:下載地址
如對(duì)本文有任何疑問(wèn),煩請(qǐng)留言區(qū)提出,看到馬上都會(huì)回復(fù)。如果本文中有任何錯(cuò)誤,請(qǐng)您指正,我會(huì)馬上進(jìn)行更改。