WWDC 2013 Session笔记 - iOS7中的多任务
這是我的WWDC2013系列筆記中的一篇,完整的筆記列表請參看這篇總覽。本文僅作為個人記錄使用,也歡迎在許可協(xié)議范圍內(nèi)轉(zhuǎn)載或使用,但是還煩請保留原文鏈接,謝謝您的理解合作。如果您覺得本站對您能有幫助,您可以使用RSS或郵件方式訂閱本站,這樣您將能在第一時間獲取本站信息。
本文涉及到的WWDC2013 Session有
- Session 204 What's New with Multitasking
- Session 705 What’s New in Foundation Networking
iOS7以前的Multitasking
iOS的多任務(wù)是在iOS4的時候被引入的,在此之前iOS的app都是按下Home鍵就被干掉了。iOS4雖然引入了后臺和多任務(wù),但是實際上是偽多任務(wù),一般的app后臺并不能執(zhí)行自己的代碼,只有少數(shù)幾類服務(wù)在通過注冊后可以真正在后臺運行,并且在提交到AppStore的時候也會被嚴(yán)格審核是否有越權(quán)行為,這種限制主要是出于對于設(shè)備的續(xù)航和安全兩方面進行的考慮。之后經(jīng)過iOS5和6的逐漸發(fā)展,后臺能運行的服務(wù)的種類雖然出現(xiàn)了增加,但是iOS后臺的本質(zhì)并沒有變化。在iOS7之前,系統(tǒng)所接受的應(yīng)用多任務(wù)可以大致分為幾種:
- 后臺完成某些花費時間的特定任務(wù)
- 后臺播放音樂等
- 位置服務(wù)
- IP電話(VoIP)
- Newsstand
在WWDC 2013的keynote上,iOS7的后臺多任務(wù)改進被專門拿出來向開發(fā)者進行了介紹,到底iOS7里多任務(wù)方面有什么新的特性可以利用,如何使用呢?簡單來說,iOS7在后臺特性方面有很大改進,不僅改變了以往的一些后臺任務(wù)處理方式,還加入了全新的后臺模式,本文將針對iOS7中新的后臺特性進行一些學(xué)習(xí)和記錄。大體來說,iOS7后臺的變化在于以下四點:
- 改變了后臺任務(wù)的運行方式
- 增加了后臺獲取(Background Fetch)
- 增加了推送喚醒(靜默推送,Silent Remote Notifications)
- 增加了后臺傳輸(Background Transfer Service)
iOS7的多任務(wù)
后臺任務(wù)
首先看看后臺任務(wù)的變化,先說這方面的改變,而不是直接介紹新的API,是因為這個改變很典型地代表了iOS7在后臺任務(wù)管理和能耗控制上的大體思路。從上古時期開始(其實也就4.0),UIApplication提供了-beginBackgroundTaskWithExpirationHandler:方法來使app在被切到后臺后仍然能保持運行一段時間,app可以用這個方法來確保一些很重很慢的工作可以在急不可耐的用戶將你的應(yīng)用扔到后臺后還能完成,比如編碼視頻,上傳下載某些重要文件或者是完成某些數(shù)據(jù)庫操作等,雖然時間不長,但在大多數(shù)情況下勉強夠用。如果你之前沒有使用過這個API的話,它使用起來大概是長這個樣子的:
- (void) doUpdatedispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{[self beginBackgroundUpdateTask];NSURLResponse * response = nil;NSError * error = nil;NSData * responseData = [NSURLConnection sendSynchronousRequest: request returningResponse: &response error: &error];// Do something with the result[self endBackgroundUpdateTask];}); }- (void) beginBackgroundUpdateTask {self.backgroundUpdateTask = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:^{[self endBackgroundUpdateTask];}]; }- (void) endBackgroundUpdateTask {[[UIApplication sharedApplication] endBackgroundTask: self.backgroundUpdateTask];self.backgroundUpdateTask = UIBackgroundTaskInvalid; }在beginBackgroundTaskWithExpirationHandler:里寫一個超時處理(系統(tǒng)只給app分配了一定時間來進行后臺任務(wù),超時之前會調(diào)用這個block),然后進行開始進行后臺任務(wù)處理,在任務(wù)結(jié)束或者過期的時候call一下endBackgroundTask:使之與begin方法配對(否則你的app在后臺任務(wù)超時的時候會被殺掉)。同時,你可以使用UIApplication實例的backgroundTimeRemaining屬性來獲取剩余的后臺執(zhí)行時間。
具體的執(zhí)行時間來說,在iOS6和之前的系統(tǒng)中,系統(tǒng)在用戶退出應(yīng)用后,如果應(yīng)用正在執(zhí)行后臺任務(wù)的話,系統(tǒng)會保持活躍狀態(tài)直到后臺任務(wù)完成或者是超時以后,才會進入真正的低功耗休眠狀態(tài)。
而在iOS7中,后臺任務(wù)的處理方式發(fā)生了改變。系統(tǒng)將在用戶鎖屏后盡快讓設(shè)備進入休眠狀態(tài),以節(jié)省電力,這時后臺任務(wù)是被暫停的。之后在設(shè)備在特定時間進行系統(tǒng)應(yīng)用的操作被喚醒(比如檢查郵件或者接到來電等)時,之前暫停的后臺任務(wù)將一起進行。就是說,系統(tǒng)不會專門為第三方的應(yīng)用保持設(shè)備處于活動狀態(tài)。如下圖示
這個變化在不減少應(yīng)用的后臺任務(wù)時間長度的情況下,給設(shè)備帶來了更多的休眠時間,從而延長了續(xù)航。對于開發(fā)者來說,這個改變更多的是系統(tǒng)層級的變化,對于非網(wǎng)絡(luò)傳輸?shù)娜蝿?wù)來說,保持原來的用法即可,新系統(tǒng)將會按照新的喚醒方式進行處理;而對于原來在后臺做網(wǎng)絡(luò)傳輸?shù)膽?yīng)用來說,蘋果建議在iOS7中使用NSURLSession,創(chuàng)建后臺的session并進行網(wǎng)絡(luò)傳輸,這樣可以很容易地利用更好的后臺傳輸API,而不必受限于原來的時長,關(guān)于這個具體的我們一會兒再說。
后臺獲取(Background Fetch)
現(xiàn)在的應(yīng)用無法在后臺獲取信息,比如社交類應(yīng)用,用戶一定需要在打開應(yīng)用之后才能進行網(wǎng)絡(luò)連接,獲取新的消息條目,然后才能將新內(nèi)容呈現(xiàn)給用戶。說實話這個體驗并不是很好,用戶在打開應(yīng)用后必定會有一段時間的等待,每次皆是如此。iOS7中新加入的后臺獲取就是用來解決這個不足的:后臺獲取干的事情就是在用戶打開應(yīng)用之前就使app有機會執(zhí)行代碼來獲取數(shù)據(jù),刷新UI。這樣在用戶打開應(yīng)用的時候,最新的內(nèi)容將已然呈現(xiàn)在用戶眼前,而省去了所有的加載過程。想想看,沒有加載的網(wǎng)絡(luò)體驗的世界,會是怎樣一種感覺。這已經(jīng)不是smooth,而是真的amazing了。
那具體應(yīng)該怎么做呢?一步一步來:
啟用后臺獲取
首先是修改應(yīng)用的Info.plist,在UIBackgroundModes中加入fetch,即可告訴系統(tǒng)應(yīng)用需要后臺獲取的權(quán)限。另外一種更簡單的方式,得益于Xcode5的Capabilities特性(參見可以參見我之前的一篇WWDC2013筆記 Xcode5和ObjC新特性),現(xiàn)在甚至都不需要去手動修改Info.plist來進行添加了,打開Capabilities頁面下的Background Modes選項,并勾選Background fetch選項即可(如下圖)。
筆者寫這篇文章的時候iOS7還沒有上市,也沒有相關(guān)的審核資料,所以不知道如果只是在這里打開了fetch選項,但卻沒有實現(xiàn)的話,應(yīng)用會不會無法通過審核。但是依照蘋果一貫的做法來看,如果聲明了需要某項后臺權(quán)限,但是結(jié)果卻沒有相關(guān)實現(xiàn)的話,被拒掉的可能性還是比較大的。因此大家盡量不要拿上線產(chǎn)品進行實驗,而應(yīng)當(dāng)是在demo項目里研究明白以后再到上線產(chǎn)品中進行實裝。
設(shè)定獲取間隔
對應(yīng)用的UIApplication實例設(shè)置獲取間隔,一般在應(yīng)用啟動的時候調(diào)用以下代碼即可:
[[UIApplication sharedApplication] setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];如果不對最小后臺獲取間隔進行設(shè)定的話,系統(tǒng)將使用默認值UIApplicationBackgroundFetchIntervalNever,也就是永遠不進行后臺獲取。當(dāng)然,-setMinimumBackgroundFetchInterval:方法接受的是NSTimeInterval,因此你也可以手動指定一個以秒為單位的最小獲取間隔。需要注意的是,我們都已經(jīng)知道iOS是一個非常霸道為我獨尊的系統(tǒng),因此自然也不可能讓一介區(qū)區(qū)第三方應(yīng)用來控制系統(tǒng)行為。這里所指定的時間間隔只是代表了“在上一次獲取或者關(guān)閉應(yīng)用之后,在這一段時間內(nèi)一定不會去做后臺獲取”,而真正具體到什么時候會進行后臺獲取,那~完全是要看系統(tǒng)娘的心情的~我們是無從得知的。系統(tǒng)將根據(jù)你的設(shè)定,選擇比如接收郵件的時候順便為你的應(yīng)用獲取一下,或者也有可能專門為你的應(yīng)用喚醒一下設(shè)備。作為開發(fā)者,我們應(yīng)該做的是為用戶的電池考慮,盡可能地選擇合適自己應(yīng)用的后臺獲取間隔。設(shè)置為UIApplicationBackgroundFetchIntervalMinimum的話,系統(tǒng)會盡可能多盡可能快地為你的應(yīng)用進行后臺獲取,但是比如對于一個天氣應(yīng)用,可能對實時的數(shù)據(jù)并不會那么關(guān)心,就完全不必設(shè)置為UIApplicationBackgroundFetchIntervalMinimum,也許1小時會是一個更好的選擇。新的Mac OSX 10.9上已經(jīng)出現(xiàn)了功耗監(jiān)測,用于讓用戶確定什么應(yīng)用是能耗大戶,有理由相信同樣的東西也可能出現(xiàn)在iOS上。如果不想讓用戶因為你的應(yīng)用是耗電大戶而怒刪的話,從現(xiàn)在開始注意一下應(yīng)用的能耗還是蠻有必要的(做綠色環(huán)保低碳的iOS app,從今天開始~)。
實現(xiàn)后臺獲取代碼并通知系統(tǒng)
在完成了前兩步后,只需要在AppDelegate里實現(xiàn)-application:performFetchWithCompletionHandler:就行了。系統(tǒng)將會在執(zhí)行fetch的時候調(diào)用這個方法,然后開發(fā)者需要做的是在這個方法里完成獲取的工作,然后刷新UI,并通知系統(tǒng)獲取結(jié)束,以便系統(tǒng)盡快回到休眠狀態(tài)。獲取數(shù)據(jù)這是應(yīng)用相關(guān)的內(nèi)容,在此不做贅述,應(yīng)用在前臺能完成的工作在這里都能做,唯一的限制是系統(tǒng)不會給你很長時間來做fetch,一般會小于一分鐘,而且fetch在絕大多數(shù)情況下將和別的應(yīng)用共用網(wǎng)絡(luò)連接。這些時間對于fetch一些簡單數(shù)據(jù)來說是足夠的了,比如微博的新條目(大圖除外),接下來一小時的天氣情況等。如果涉及到較大文件的傳輸?shù)脑?#xff0c;用后臺獲取的API就不合適了,而應(yīng)該使用另一個新的文件傳輸?shù)腁PI,我們稍后再說。類似前面提到的后臺任務(wù)完成時必須通知系統(tǒng)一樣,在在獲取完成后,也必須通知系統(tǒng)獲取完成,方法是調(diào)用-application:performFetchWithCompletionHandler:的handler。這個CompletionHandler接收一個UIBackgroundFetchResult作為參數(shù),可供選擇的結(jié)果有UIBackgroundFetchResultNewData,UIBackgroundFetchResultNoData,UIBackgroundFetchResultFailed三種,分別表示獲取到了新數(shù)據(jù)(此時系統(tǒng)將對現(xiàn)在的UI狀態(tài)截圖并更新App Switcher中你的應(yīng)用的截屏),沒有新數(shù)據(jù),以及獲取失敗。寫一個簡單的例子吧:
//File: YourAppDelegate.m -(void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler {UINavigationController *navigationController = (UINavigationController*)self.window.rootViewController;id fetchViewController = navigationController.topViewController;if ([fetchViewController respondsToSelector:@selector(fetchDataResult:)]) {[fetchViewController fetchDataResult:^(NSError *error, NSArray *results){if (!error) {if (results.count != 0) {//Update UI with results.//Tell system all done.completionHandler(UIBackgroundFetchResultNewData);} else {completionHandler(UIBackgroundFetchResultNoData);}} else {completionHandler(UIBackgroundFetchResultFailed);}}];} else {completionHandler(UIBackgroundFetchResultFailed);} }當(dāng)然,實際情況中會比這要復(fù)雜得多,用戶當(dāng)前的ViewController是否合適做獲取,獲取后的數(shù)據(jù)如何處理都需要考慮。另外要說明的是上面的代碼在獲取成功后直接在appDelegate里更新UI,這只是為了能在同一處進行說明,但卻是不正確的結(jié)構(gòu)。比較好的做法是將獲取和更新UI的業(yè)務(wù)邏輯都放到fetchViewController里,然后向其發(fā)送獲取消息的時候?qū)ompletionHandler作為參數(shù)傳入,并在fetchViewController里完成獲取結(jié)束的報告。
另一個比較神奇的地方是系統(tǒng)將追蹤用戶的使用習(xí)慣,并根據(jù)對每個應(yīng)用的使用時刻給一個合理的fetch時間。比如系統(tǒng)將記錄你在每天早上9點上班的電車上,中午12點半吃飯時,以及22點睡覺前會刷一下微博,只要這個習(xí)慣持續(xù)個三四天,系統(tǒng)便會將應(yīng)用的后臺獲取時刻調(diào)節(jié)為9點,12點和22點前一點。這樣在每次你打開應(yīng)用都直接有最新內(nèi)容的同時,也節(jié)省了電量和流量。
后臺獲取的調(diào)試
既然是系統(tǒng)決定的fetch,那我們要如何測試寫的代碼呢?難道是將應(yīng)用退到后臺,然后安心等待系統(tǒng)進行后臺獲取么?當(dāng)然不是...Xcode5為我們提供了兩種方法來測試后臺獲取的代碼。一種是從后臺獲取中啟動應(yīng)用,另一種是當(dāng)應(yīng)用在后臺時模擬一次后臺推送。
對于前者,我們可以新建一個Scheme來專門調(diào)試從后臺啟動。點擊Xcode5的Product->Scheme->Edit Scheme(或者直接使用快捷鍵?<)。在編輯Scheme的窗口中點Duplicate Scheme按鈕復(fù)制一個當(dāng)前方案,然后在新Scheme的option中將Background Fetch打上勾。從這個Scheme來運行應(yīng)用的時候,應(yīng)用將不會直接啟動切入前臺,而是調(diào)用后臺獲取部分代碼并更新UI,這樣再點擊圖標(biāo)進入應(yīng)用時,你應(yīng)該可以看到最新的數(shù)據(jù)和更新好的UI了。
另一種是當(dāng)應(yīng)用在后臺時,模擬一次后臺獲取。這個比較簡單,在app調(diào)試運行時,點擊Xcode5的Debug菜單中的Simulate Background Fetch,即可模擬完成一次獲取調(diào)用。
推送喚醒(Remote Notifications)
遠程推送(Remote Push Notifications)可以說是增加用戶留存率的不二法則,在iOS6和之前,推送的類型是很單一的,無非就是顯示標(biāo)題內(nèi)容,指定聲音等。用戶通過解鎖進入你的應(yīng)用后,appDelegate中通過推送打開應(yīng)用的回調(diào)將被調(diào)用,然后你再獲取數(shù)據(jù),進行顯示。這和沒有后臺獲取時的打開應(yīng)用后再獲取數(shù)據(jù)刷新的問題是一樣的。在iOS7中這個行為發(fā)生了一些改變,我們有機會使設(shè)備在接收到遠端推送后讓系統(tǒng)喚醒設(shè)備和我們的后臺應(yīng)用,并先執(zhí)行一段代碼來準(zhǔn)備數(shù)據(jù)和UI,然后再提示用戶有推送。這時用戶如果解鎖設(shè)備進入應(yīng)用后將不會再有任何加載過程,新的內(nèi)容將直接得到呈現(xiàn)。
實裝的方法和剛才的后臺獲取比較類似,還是一步步來:
啟用推送喚醒
和上面的后臺獲取類似,更改Info.plist,在UIBackgroundModes下加入remote-notification即可開啟,當(dāng)然同樣的更簡單直接的辦法是使用Capabilities。
更改推送的payload
在iOS7中,如果想要使用推送來喚醒應(yīng)用運行代碼的話,需要在payload中加入content-available,并設(shè)置為1。
aps {content-available: 1alert: {...}}
實現(xiàn)推送喚醒代碼并通知系統(tǒng)
最后在appDelegate中實現(xiàn)-application:didReceiveRemoteNotification:fetchCompletionHandle:。這部分內(nèi)容和上面的后臺獲取部分完全一樣,在此不再重復(fù)。
一些限制和應(yīng)用的例子
因為一旦推送成功,用戶的設(shè)備將被喚醒,因此這類推送不可能不受到限制。Apple將限制此類推送的頻率,當(dāng)頻率超過一定限制后,帶有content-available標(biāo)志的推送將會被阻塞,以保證用戶設(shè)備不被頻繁喚醒。按照Apple的說法,這個頻率在一小時內(nèi)個位數(shù)次的推送的話不會有太大問題。
Apple給出了幾個典型的應(yīng)用情景,比如一個電視節(jié)目類的應(yīng)用,當(dāng)用戶標(biāo)記某些劇目為喜愛時,當(dāng)這些劇有更新時,可以給用戶發(fā)送靜默的喚醒推送通知,客戶端在接到通知后檢查更新并開始后臺下載(注意后臺下載的部分絕對不應(yīng)該在推送回調(diào)中做,而是應(yīng)該使用新的后臺傳輸服務(wù),后面詳細介紹)。下載完成后發(fā)送一個本地推送告知用戶新的內(nèi)容已經(jīng)準(zhǔn)備完畢。這樣在用戶注意到推送并打開應(yīng)用的時候,所有必要的內(nèi)容已經(jīng)下載完畢,UI也將切換至用戶喜愛的劇目,用戶只需要點擊播放即可開始真正使用應(yīng)用,這絕對是無比順暢和優(yōu)秀的體驗。另一種應(yīng)用情景是文件同步類,比如用戶標(biāo)記了一些文件為需要隨時同步,這樣用戶在其他設(shè)備或網(wǎng)頁服務(wù)上更改了這些文件時,可以發(fā)送靜默推送然后使用后臺傳輸來保持這些文件隨時是最新。
如果您是一路看下來的話,不難發(fā)現(xiàn)其實后臺獲取和靜默推送在很多方面是很類似的,特別是實現(xiàn)和處理的方式,但是它們適用的情景是完全不同的。后臺獲取更多地使用在泛數(shù)據(jù)模式下,也即用戶對特定數(shù)據(jù)并不是很關(guān)心,數(shù)據(jù)應(yīng)該被更新的時間也不是很確定,典型的有社交類應(yīng)用和天氣類應(yīng)用;而靜默推送或者是推送喚醒更多地應(yīng)該是用戶感興趣的內(nèi)容發(fā)生更新時被使用,比如消息類應(yīng)用和內(nèi)容型服務(wù)等。根據(jù)不同的應(yīng)用情景,選擇合適的后臺策略(或者混合使用兩者),以帶給用戶絕佳體驗,這是Apple所期望iOS7開發(fā)者做到的。
后臺傳輸(Background Transfer Service)
iOS6和之前,iOS應(yīng)用在大塊數(shù)據(jù)的下載這一塊限制是比較多的:只有應(yīng)用在前臺時能保持下載(用戶按Home鍵切到后臺或者是等到設(shè)備自動休眠都可能中止下載),在后臺只有很短的最多十分鐘時間可以保持網(wǎng)絡(luò)連接。如果想要完成一個較大數(shù)據(jù)的下載,用戶將不得不打開你的app并且基本無所事事。很多這種時候,用戶會想要是在下載的時候能切到別的應(yīng)用刷刷微博或者玩玩游戲,然后再切回來的就已經(jīng)下載完成了的話,該有多好。iOS7中,這可以實現(xiàn)了。iOS7引入了后臺傳輸?shù)南嚓P(guān)方式,用來保證應(yīng)用退出后數(shù)據(jù)下載或者上傳能繼續(xù)進行。這種傳輸是由iOS系統(tǒng)進行管理的,沒有時間限制,也不要求應(yīng)用運行在前臺。
想要實現(xiàn)后臺傳輸,就必須使用iOS7的新的網(wǎng)絡(luò)連接的類,NSURLSession。這是iOS7中引入用以替代陳舊的NSURLConnection的類,著名的AFNetworking甚至不惜從底層開始完全重寫以適配iOS7和NSURLSession(參見這里),NSURLSession的重要性可見一斑。在這里我主要只介紹NSURLSession在后臺傳輸中的一些使用,關(guān)于這個類的其他用法和對原有NSURLConnection的加強,只做稍微帶過而不展開,有興趣深入挖掘和使用的童鞋可以參看Apple的文檔(或者更簡單的方式是使用AFNetworking來處理網(wǎng)絡(luò)相關(guān)內(nèi)容,而不是直接和CFNetwork框架打交道)。
步驟和例子
后臺傳輸?shù)牡膶崿F(xiàn)也十分簡單,簡單說分為三個步驟:創(chuàng)建后臺傳輸用的NSURLSession對象;向這個對象中加入對應(yīng)的傳輸?shù)腘SURLSessionTask,并開始傳輸;在實現(xiàn)appDelegate里實現(xiàn)-application:handleEventsForBackgroundURLSession:completionHandler:方法,以刷新UI及通知系統(tǒng)傳輸結(jié)束。接下來結(jié)合代碼來看一看實際的用法吧~
首先我們需要一個用于后臺下載的session:
- (NSURLSession *)backgroundSession {//Use dispatch_once_t to create only one background session. If you want more than one session, do with different identifierstatic NSURLSession *session = nil;static dispatch_once_t onceToken;dispatch_once(&onceToken, ^{NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration backgroundSessionConfiguration:@"com.yourcompany.appId.BackgroundSession"];session = [NSURLSession sessionWithConfiguration:configuration delegate:self delegateQueue:nil];});return session; }這里創(chuàng)建并配置了NSURLSession,將其指定為后臺session并設(shè)定delegate。
接下來向其中加入對應(yīng)的傳輸用的NSURLSessionTask,并啟動下載。
//@property (nonatomic) NSURLSession *session; //@property (nonatomic) NSURLSessionDownloadTask *downloadTask;- (NSURLSession *)backgroundSession {//... }- (void) beginDownload {NSURL *downloadURL = [NSURL URLWithString:DownloadURLString];NSURLRequest *request = [NSURLRequest requestWithURL:downloadURL];self.session = [self backgroundSession];self.downloadTask = [self.session downloadTaskWithRequest:request];[self.downloadTask resume]; }最后一步是在appDelegate中實現(xiàn)-application:handleEventsForBackgroundURLSession:completionHandler:
//AppDelegate.m - (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifiercompletionHandler:(void (^)())completionHandler {//Check if all transfers are done, and update UI//Then tell system background transfer over, so it can take new snapshot to show in App SwitchercompletionHandler();//You can also pop up a local notification to remind the user//... }NSURLSession和對應(yīng)的NSURLSessionTask有以下重要的delegate方法可以使用:
- (void)URLSession:(NSURLSession *)session downloadTask:(NSURLSessionDownloadTask *)downloadTaskdidFinishDownloadingToURL:(NSURL *)location; - (void)URLSession:(NSURLSession *)session task:(NSURLSessionTask *)taskdidCompleteWithError:(NSError *)error;一旦后臺傳輸?shù)臓顟B(tài)發(fā)生變化(包括正常結(jié)束和失敗)的時候,應(yīng)用將被喚醒并運行appDelegate中的回調(diào),接下來NSURLSessionTask的委托方法將在后臺被調(diào)用。雖然上面的例子中直接在appDelegate中call了completionHandler,但是實際上更好的選擇是在appDelegate中暫時持有completionHandler,然后在NSURLSessionTask的delegate方法中檢查是否確實完成了傳輸并更新UI后,再調(diào)用completionHandler。另外,你的應(yīng)用到現(xiàn)在為止只是在后臺運行,想要提醒用戶傳輸完成的話,也許你還需要在這個時候發(fā)送一個本地推送(記住在這個時候你的應(yīng)用是可以執(zhí)行代碼的,雖然是在后臺),這樣用戶可以注意到你的應(yīng)用的變化并回到應(yīng)用,并開始已經(jīng)準(zhǔn)備好數(shù)據(jù)和界面。
一些限制
首先,后臺傳輸只會通過wifi來進行,用戶大概也不會開心蜂窩數(shù)據(jù)的流量被后臺流量用掉。后臺下載的時間與以前的關(guān)閉應(yīng)用后X分鐘的模式不一樣,而是為了節(jié)省電力變?yōu)殡x散式的下載,并與其他后臺任務(wù)并發(fā)(比如接收郵件等)。另外還需要注意的是,對于下載后的內(nèi)容不要忘記寫到應(yīng)用的目錄下(一般來說這種可以重復(fù)獲得的內(nèi)容應(yīng)該放到cache目錄下),否則如果由于應(yīng)用完全退出的情況導(dǎo)致沒有保存到可再次訪問的路徑的話,那可就白做工了。
后臺傳輸非常適合用于文件,照片或者追加游戲內(nèi)容關(guān)卡等的下載,如果配合后臺獲取或者靜默推送的話,相信可以完全很多很有趣,并且以前被限制而無法實現(xiàn)的功能。
轉(zhuǎn)載自:https://onevcat.com/
總結(jié)
以上是生活随笔為你收集整理的WWDC 2013 Session笔记 - iOS7中的多任务的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Linux x64 下 Matlab R
- 下一篇: [bmgr]android应用数据备份以