1. 程式人生 > >介紹 iOS7 引入的多工處理機制之Background Fetch

介紹 iOS7 引入的多工處理機制之Background Fetch

Overview

從 IOS4到 IOS7,Apple 在多工處理上不斷改進、優化。但 Apple 的態度一直很謹慎,其考慮的因素主要有兩個:記憶體和電池續航能力。

是的,如果 Apple 完全放開多工機制,那麼,首當其衝的就是電池了,有限的記憶體恐怕也很快就會消耗殆盡,從而影響當前正在前臺執行的程式。

在介紹 Apple 是如何處理多工前,先了解一下 App 的幾種不同狀態:

ok,App 不同狀態間轉換可概括為下圖

下面,我們回顧一下 Apple 在多工上的改進、優化之路:

  1. iOS4之前想實現多工,Apple 只會驕傲地說一句:”no way!”,只要按 HOME 鍵切後臺,app 立馬被終止;
  2. 嚴格的單任務執行似乎對不起”智慧機””這個榮譽稱號,因此從 iOS4開始 Apple 允許某些特定功能的 app 在後臺執行,如:Play audio、VoIP以及Receive location updates等;
  3. 從 iOS5開始,按 HOME 鍵只是暫停 app 的執行,而不是終止,其最大的好處在於保留了 app 的狀態;
  4. iOS6引入了”State Preservation and Restoration”的概念,在 app 終止前儲存狀態、下次啟動時再恢復狀態,從而給使用者一個錯覺——好像 app從來沒有退出過一樣;
  5. 高大上的 iOS7則引入更多的多工 API,包括:Background fetch、Background transfer以及Silent push notifications。

The new app switcher

在介紹 iOS7的多工機制前,還要介紹一下 iOS7對 app switcher 的改進。

從iOS4到iOS6,app switcher非常簡單,只列出了那些曾經開啟過的 app

iOS7對 app switcher 進行了改進,在 app switcher 中能展示 app 最新的狀態

每當 app 因後臺執行任務而被喚醒時,系統都會提供一個completion handler,當後臺任務完成時,我們必須執行這個completion handler,其作用不僅在於告訴裝置可以進入睡眠狀態,同時會更新 app switcher 的snapshot。
app swithcer 還扮演著任務控制中心的角色,當用戶從 app switcher清除某個 app 時,該 app 的大多數後臺任務都將結束,如:background fetches, play music等,但background transfers依然可以進行。

ok, 下面我們就要今天的主題了!

Background fetch

在 iOS7之前,當我們開啟某個 app 時,該 app 總是先顯示快取的老資料(沒做快取的惡劣 app 恐怕只能以轉菊花來消磨時間了!),然後耐心地等待網路返回新資料。
這無疑是在浪費使用者的時間,而”浪費別人的時間,就等於…”

iOS7給了我們一個改過自新的機會——通過Background fetch可以在後臺悄悄地把資料拉回來!

Background fetch通過特定的演算法週期性地喚醒 frequently-used apps 在後臺下載新資料。因此,當用戶再次開啟 app 時,看到的資料已經是最新的了,這是多麼 cool 的體驗!

那麼,要實現這麼 cool 的功能是不是很複雜?

no,only need three steps,its so easy!

  1. 允許 app 通過 Background fetch 下載資料;
  2. application:didFinishLaunchingWithOptions:方法中設定週期性拉取資料的時間間隔;
  3. 實現application:performFetchWithCompletionHandler:方法,在該方法中處理 Background fetch 的具體任務。

Background fetch的開關

這一步很簡單,點兩下滑鼠就搞定!

設定時間間隔

- (void)setMinimumBackgroundFetchInterval:(NSTimeInterval)minimumBackgroundFetchInterval通過該函式可以設定系統喚醒 app 在後臺執行Background fetch操作的時間間隔。

關於時間間隔有幾個要注意的問題:

  1. 該屬性的默值是UIApplicationBackgroundFetchIntervalNever,也就是永遠不會執行Background fetch操作。因此,如果期望 app 能執行Background fetch,就必須設定該屬性為一個合理的值;
  2. 該屬性值只是一個建議值,而不是精確的值,系統將會綜合各種因素決定什麼時侯執行Background fetch操作,但可以肯定的是時間間隔肯定不會小於該值(圖片來自 WWDC2013);

系統會收集使用者使用 app 的習慣,預測使用者在什麼時侯使用 app,從而決定什麼時間執行 app 的Background fetch 操作。
比如:系統收集到使用者習慣在早上9:00左右開啟某新聞 app,則系統可能會在8:45喚醒該 app 執行Background fetch操作拉取最新的新聞資料(圖片來自 WWDC2013)。

為了不干擾系統的這種自我學習能力,不要頻繁的執行Background fetch操作,儘量使用系統預定義的值:UIApplicationBackgroundFetchIntervalMinimum

1
2
3
4
5
6
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    [application setMinimumBackgroundFetchInterval:UIApplicationBackgroundFetchIntervalMinimum];
    
    return YES;
}

實現performFetchWithCompletionHandler方法

當系統允許 app 執行 Background fetch 操作時,會在後臺喚醒該 app,流程如下(圖片來自 WWDC2013):

application:performFetchWithCompletionHandler:方法中要完成的任務有:獲取資料、管理資料以及更新 UI 等。

同樣,作為善後工作,我們必須呼叫系統提供的completion handler,該completion handler接受一個UIBackgroundFetchResult型別的引數。

系統為UIBackgroundFetchResult預定義了3個值:

  1. UIBackgroundFetchResultNoData—沒有獲取到新資料;
  2. UIBackgroundFetchResultNewData—獲取到了新資料;
  3. UIBackgroundFetchResultFailed—獲取失敗。

Testing the Background Fetch

對於Background Fetch,我們該如何去測試呢?

有兩種方法可以去測試Background Fetch

第一種方法稍微複雜一點,需要生成新的scheme。




ok,通過這幾步,app 直接在後臺被喚醒,執行Background Fetch操作。

第二種方法是 app 正在前臺執行時,操作Background Fetch操作。

是不是很簡單!

ok,今天就到這裡了,下期將介紹另外一種Multitasking機制:Silent push notifications