本文主要是看了WWDC 2013 - Session 204 - What's New with Multitasking 做出的翻譯和總結(jié), 文字/視頻鏈接如下
該session主要講的是iOS7比iOS6在多任務(wù)管理上新增了這些API.
- 后臺應(yīng)用刷新
- 遠程推送
- 后臺傳輸服務(wù)
iOS6的時候, 盡管你鎖屏了, 一些程序的后臺任務(wù)也會繼續(xù)運行直到完成.
iOS7的時候做了改進, 鎖屏之后手機很快就會進入睡眠狀態(tài), 任務(wù)就會被掛起 但是, 當手機被喚醒了, 例如在看郵件的時候, 你的應(yīng)用程序就能利用這些時間片去繼續(xù)執(zhí)行后臺任務(wù).
iOS7之后, 建議使用NSURLSession
.
應(yīng)用程序進入后臺后仍然有幾分鐘的時間可以處理任務(wù), 但是這幾分鐘不保證是連續(xù)的. 也就是說有可能會被強行中斷, 例如內(nèi)存不足的時候系統(tǒng)會殺死后臺應(yīng)用程序.
新概念 :
App Switcher, app在進入后臺之前系統(tǒng)會先拍個快照, 這樣你在切換應(yīng)用程序的界面就會看到退出時的app的界面. 這種行為為 : State Restoration
需要注意的是 : 在App Switch劃走app在iOS6的時候只會停止app runnning(仍處于Background狀態(tài)), 而在iOS7則還會停止app running in the background. 所以現(xiàn)在一些使用到GPS或者實時位置更新的app在被劃走之后這些功能就會停止運行, 你不會在后臺收到任何通知.
首先, iOS7新增的多任務(wù)處理的API分為三大種
Background Fetch
: 后臺獲取, 供進入后臺的app的能周期性地更新他的內(nèi)容.Remote Notification
: 遠程通知, 當你發(fā)送一個很重要的通知時, 他能夠從后臺喚醒你的app. 例如即時通訊的消息等Background Transfer Service
: 后臺傳輸服務(wù), 他允許在用戶離開你的app后(回到桌面)通過自啟動在后臺隊列中執(zhí)行上傳和下載任務(wù).
后臺應(yīng)用刷新
后臺應(yīng)用刷新能保證每當你的app進入onFocus狀態(tài)的時候用戶看到的都是最新的內(nèi)容, 而不是他們之前退出時(舊)的內(nèi)容.
使用用法 :
在info.plist中把
Background Fetch
這個key添加到UI background modes
中.-
設(shè)置后臺獲取的
minimum fetch interval
, 最小時間間隔- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { /* * 默認是UIApplicationBackgroundFetchIntervalNever. */ [application setMinimumBackgroundFetchInterval:3600]; return YES; }
-
當時間到了的時候, 你的應(yīng)用程序?qū)?launch/resume)調(diào)用以下方法. 你唯一需要做的就是實現(xiàn)這個方法, 發(fā)送網(wǎng)絡(luò)請求, 接收響應(yīng)數(shù)據(jù)并刷新UI.
- (void)application:(UIApplication *)application performFetchWithCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { // go to fetch your new content here // go to update UI here // 做完所有處理后一定要調(diào)用completionHandler block 告訴系統(tǒng) }
最小時間間隔
需要注意的是, 當你的應(yīng)用是剛下載好的, 用戶還沒登陸時, 這個值應(yīng)為never. 當用戶登陸之后, 這個值可以告訴系統(tǒng), 讓系統(tǒng)在適當?shù)臅r間間隔下啟動你的應(yīng)用并發(fā)起網(wǎng)絡(luò)請求并更新UI(例如更新用戶狀態(tài)信息等). 當然, 如果用戶退出登陸了, 你應(yīng)該設(shè)置這個值為never.
例如你設(shè)置了5秒鐘, 則代表app在退出到后臺運行的5秒鐘以內(nèi)是不會調(diào)用該API的, 只有在5秒鐘之后才有可能去獲取數(shù)據(jù). 也就是說, 應(yīng)用在進入后臺后的interval這個時間段內(nèi)是不會被喚醒的.
問題來了, 這有什么用? 我肯定希望我的app任何時候都能自動更新然后每次用戶進入我app的時候顯示的都是最新的內(nèi)容啊! 這么想就太自私了, 因為用戶手機有電量, 流量等等各種限制. 例如, 抓取某幾個地區(qū)的天氣數(shù)據(jù), 這是個很耗流量, 電量且耗服務(wù)器資源的操作, 此時你不會想每隔1分鐘他就發(fā)起一個網(wǎng)絡(luò)請求吧? 你會傾向于1個小時或者更長的時間去請求, 這能節(jié)省資源, 提高用戶體驗.
需要注意的是, 不應(yīng)該把delegate方法中的completionHandler
當做property存儲起來再調(diào)用, 而是應(yīng)該通過方法傳遞待完成后直接調(diào)用. 因為當后臺刷新同時出現(xiàn)兩次的時候, 第二次的block就會把第一次的block給覆蓋掉(假如是用property存儲的話), 那意味著第一次的block永遠無法被調(diào)用. 切記!
當iOS系統(tǒng)中同一時間有多個后臺獲取任務(wù)的時候, 系統(tǒng)就能在一個時間段內(nèi)處理這些任務(wù), 而不是零零散散地處理, 那會加大電池損耗. 但是一個時間段內(nèi)的任務(wù)太多了也是會增大電量的損耗的.
更為牛逼的是, iOS系統(tǒng)做了如此的優(yōu)化. 他用一個observer觀察用戶真實的使用習慣, 例如我每天早上7點鐘打開簡書看文章, 每天中午12點打開簡書, 每天晚上10點打開簡書. 那么系統(tǒng)就會記錄起這個模式. 之后就會盡可能在我打開app之前就做好這個后臺應(yīng)用刷新的工作.
如果我們不需要后臺應(yīng)用刷新的服務(wù), 可以自行在設(shè)置 -> 通用 -> 后臺應(yīng)用刷新里關(guān)掉這個功能. 畢竟有時候我們真的電量不足了, 或是流量不夠用了...
遠程通知
當我發(fā)一個消息給我朋友的時候, 實際上是我先發(fā)給蘋果的服務(wù)器, 然后蘋果服務(wù)器再下發(fā)給我朋友的設(shè)備, 然后他才接收到消息/彈窗.
另外, 還能發(fā)一個Silent Notification(不帶消息的通知), 他會在后臺交付然后launch/resume你的app, 并執(zhí)行一些你自定義的任務(wù).
Silent Notification配置在這里
使用方法 :
在info.plist中把
remote-notification
這個key添加到UI background modes
中.-
當你發(fā)送一個遠程通知之后, app就會被launch/resume
- (void)application:(UIApplication *)application didReceiveRemoteNotification:(NSDictionary *)userInfo fetchCompletionHandler:(void (^)(UIBackgroundFetchResult))completionHandler { // do something here // remember call completionHandler block when finished work }
然而, 通知發(fā)得太頻繁的話, 你的設(shè)備和蘋果的服務(wù)器會限制你的發(fā)送頻率. 蘋果的服務(wù)器會先把你的一些通知先存儲起來, 過一會再推送給用戶.
后臺刷新和遠程推送的區(qū)別
后臺刷新 | 遠程推送 | |
---|---|---|
內(nèi)容重要性 | 有意思但是不太重要 | 需要立馬讓用戶知道的 |
頻率 | 非常頻繁 | 偶爾 |
例子 | 新聞, 社交, 圖片分享 | 即時信息, 同步內(nèi)容, 稍后閱讀 |
后臺傳輸服務(wù)
iOS7后支持后臺上傳/下載. iOS會把你的上傳/下載任務(wù)放在后臺傳輸服務(wù)隊列中, 當然與此同時你的app將會被喚醒, 以便處理任務(wù)執(zhí)行過程中的任何突發(fā)事件, 并保證用戶能第一時間知道這些情況.
使用的是NSURLSession
而不是NSURLConnection
. 他可以用NSURLSessionConfiguration
來自定義該session的策略, 例如是否需要緩存, 超時等等. 顯然, 他也會launch/resume你的app.
- (void)application:(UIApplication *)application handleEventsForBackgroundURLSession:(NSString *)identifier completionHandler:(void (^)())completionHandler
{
// do something here
// remember call completionHandler block when finished work
}
由于后臺傳輸服務(wù)是多應(yīng)用并行的, 所以你要用盡可能少的時間去做UI更新操作(少于一分鐘), 同時也要保證CPU使用率不要太高. 用instrument
中的Time Profile
查看執(zhí)行時間, 優(yōu)化讓CPU執(zhí)行時間盡可能少.
一般來說人們會使用這個后臺任務(wù)API來關(guān)閉數(shù)據(jù)庫連接操作或者關(guān)閉句柄或者其他系統(tǒng)資源.
數(shù)據(jù)保護
NSFileProtection
- completeProtection表示沒鎖屏的時候數(shù)據(jù)可正常訪問, 鎖屏以后數(shù)據(jù)全部不能訪問.
- None表示有沒有鎖屏都能正常訪問.
在database, SQLite database方面我們一定要用completeProtection以保證安全.