App Programming Guide for iOS -> 處理應用狀態(tài)轉換的策略(二)

當應用進入前臺的時候該做什么

回到前臺的過程是應用重啟一些任務的機會,這些任務是在應用進入后臺的時候被停止的。圖4-4展示了應用進入前臺時所經(jīng)歷的步驟。applicationWillEnterForeground:方法應該撤銷在 applicationDidEnterBackground:方法中的操作,并在applicationDidBecomeActive:方法中繼續(xù)執(zhí)行與應用啟動時一樣的任務。

圖4-4 從后臺轉換到前臺

注意:UIApplicationWillEnterForegroundNotification通知也可用于跟蹤應用是否重新進入前臺。應用的對象可以使用默認通知中心來注冊這個通知。

準備處理通知隊列

當一個應用從掛起狀態(tài)返回到前臺或者后臺狀態(tài)的時候,它都必須為處理通知隊列做好準備。一個掛起狀態(tài)的應用,不能執(zhí)行任何代碼,所以也不能處理相關的通知,包括方向改變、時間改變、偏好改變、以及很多影響應用外觀和狀態(tài)改變的通知。為了確保這些改變沒有丟失,系統(tǒng)會把很多相關的通知組成隊列,一旦應用再次執(zhí)行代碼的時候(無論是前臺還時后臺),把它們發(fā)送給應用。為了防止應用在恢復的時候因為通知太多而導致負荷超載,系統(tǒng)會將事件合并成一個通知并發(fā)送給應用。這個通知反映了從應用被掛以來的凈更改。

表4-1 羅列了可以合并且發(fā)送到應用的通知。這些通知的大多數(shù)都可以直接發(fā)送給已注冊的觀察者。但有一些,例如與設備方向更改相關的,通常會被系統(tǒng)框架截取,并以另一種方式發(fā)送給應用。

表4-1 被發(fā)送到蘇醒應用的通知

事件 通知
連接或斷開配件 EAAccessoryDidConnectNotification
EAAccessoryDidDisconnectNotification
設備方向改變 UIDeviceOrientationDidChangeNotification
除了此通知外,視圖控制器可以自動的更新它們的界面方向。
顯著的時間變化 UIApplicationSignificantTimeChangeNotification
電池電量或者電池狀態(tài)改變 UIDeviceBatteryLevelDidChangeNotification
UIDeviceBatteryStateDidChangeNotification
接近狀態(tài)已改變 UIDeviceProximityStateDidChangeNotification
受保護文件狀態(tài)已改變 UIApplicationProtectedDataWillBecomeUnavailable
UIApplicationProtectedDataDidBecomeAvailable
連接或斷開外接顯示器 UIScreenDidConnectNotification
UIScreenDidDisconnectNotification
顯示屏的畫面模式已改變 UIScreenModeDidChangeNotification
通過Settings應用修改了首選項 NSUserDefaultsDidChangeNotification
當前語言或地區(qū)設置已改變 NSCurrentLocaleDidChangeNotification
用戶iCloud賬戶狀態(tài)已改變 NSUbiquityIdentityDidChangeNotification

通知隊列會發(fā)送到應用的主運行循環(huán),通常會先于觸摸事件和用戶輸入發(fā)送。大多數(shù)應用都能快速處理這些事件,不會造成明顯的延遲。但是,如果應用出現(xiàn)從后臺返回時過于緩慢的情況,請使用Instruments來確定是否是由處理通知的代碼導致的。

返回到前臺的應用,也可接收更新視圖的通知。運行在后臺的應用仍可以調用setNeedsDisplay 或 setNeedsDisplayInRect:方法來請求更新視圖。但是,因為這些視圖不可見,系統(tǒng)會合并這些請求,等到應用會到前臺之后再對它們進行更新。

處理iCloud的改變

無論何種原因使得iCloud狀態(tài)改變,系統(tǒng)都會向應用發(fā)送一個NSUbiquityIdentityDidChangeNotification通知。當用戶登錄或退出iCloud賬戶,或允許或禁止同步文檔和數(shù)據(jù)時,iCloud狀態(tài)都會發(fā)生改變。這個通知是應用暗示要更新緩存以及任何和iCloud相關的用戶界面元素,以適應狀態(tài)的改變。例如,當用戶注銷iCloud的時候,你應該刪除所有基于iCloud的文件或數(shù)據(jù)的引用。

如果應用已經(jīng)提醒過用戶是否存儲文件到iCloud,那么在iCloud狀態(tài)改變的時候就不再重復提醒。在第一次提醒用戶之后,在應用的本地偏好中存儲用戶的選擇。然后你可以使用Settings束或者應用中的選項來顯示該偏好。但是不要再次提醒,除非該偏好當前不在用戶默認的數(shù)據(jù)庫中。

處理區(qū)域(locale)改變

如果用戶在掛起期間改變了所在區(qū)域,那么當應用回到前臺的時候,你能使用NSCurrentLocaleDidChangeNotification通知來對任何包含區(qū)域敏感信息的視圖進行更新,例如日期、時間、數(shù)字。當然,避免區(qū)域相關問題的最好辦法是編寫代碼來讓更新視圖更容易。例如:

  • 當要取回NSLocale對象的時候,使用autoupdatingCurrentLocale類方法。該方法返回一個區(qū)域對象,它會根據(jù)區(qū)域改變而自動更新自身,因此你無需重新創(chuàng)建它。然而,當區(qū)域改變時,你仍然需要刷新含有區(qū)域派生信息的界面。
  • 一旦當前的區(qū)域信息發(fā)生改變,就應該重新創(chuàng)建任何緩存的數(shù)據(jù)及數(shù)字格式化對象。

更多關于國際化你的代碼以便處理區(qū)域改變的信息,參見Internationalization and Localization Guide。

處理應用設置的更改

如果應用由通過Settings應用管理的設置時,應用應該觀察NSUserDefaultsDidChangeNotification通知。因為用戶可以在應用掛起或者后臺期間改變設置,你能使用這個通知來回應這些設置中的重要更改。在某些情況下,響應這個通知能幫助關閉潛在的安全漏洞。例如,email程序應該響應用戶賬戶信息的改變。未對這些更改進行檢測,會導致隱私和安全方面的問題。具體來說,當前用戶可以使用舊的賬戶信息發(fā)送郵件,即使該賬戶不再屬于該用戶。

在收到NSUserDefaultsDidChangeNotification通知后,應用應該重新加載相關的設置,如有必要,重新設置它的用戶界面。如果密碼或其他安全相關的信息改變了,你還應該隱藏之前顯示的信息,并強制用戶輸入新密碼。

當應用進入后臺時該做什么

當應用從前臺進入后臺執(zhí)行時,使用applicationDidEnterBackground:方法來執(zhí)行以下操作:

  • 準備獲取應用的圖片。當applicationDidEnterBackground:方法返回時,系統(tǒng)的到一張應用用戶界面的圖片,并將這張圖片用于轉場動畫。如果視圖中包含任何敏感信息,你應該在applicationDidEnterBackground: 返回之前隱藏或修改這些界面。如果作為這個處理的一部分,你添加一個新視圖到視圖層次結構中,你必須強制這些視圖自我繪制,如Prepare for the App Snapshot中所述那樣。
  • 保存所有相關的應用狀態(tài)信息。在進入后臺之前,應用應該已經(jīng)保存了所有關鍵用戶數(shù)據(jù)。使用這個到后臺的過渡期,保存應用的最后狀態(tài)。
  • 根據(jù)需要釋放內存。釋放任何你不需要的緩存數(shù)據(jù),并盡量清理以減少應用的內存占用。占用大量內存的應用會被系統(tǒng)首先終止,所以要釋放圖像資源、數(shù)據(jù)緩存、以及其他你不再需要的對象。更多信息,參見Reduce Your Memory Footprint。

應用委托方法applicationDidEnterBackground:大概有5秒鐘來完成這些任務并返回。實際上,這些方法應該盡可能塊的返回,如果方法超過時間也沒有返回,應用會被殺死并清除出內存。如果你仍需要更多時間來執(zhí)行任務,調用beginBackgroundTaskWithExpirationHandler:方法來請求后臺執(zhí)行時間,然后在輔助線程開始長時運行任務。無論你是否開啟后臺任務, applicationDidEnterBackground:方法仍將在5秒鐘內退出。

注意:除了調用 applicationDidEnterBackground: 方法,系統(tǒng)還發(fā)送UIApplicationDidEnterBackgroundNotification通知。你可以使用這個通知來把清理任務分發(fā)到應用中的其他對象。

基于應用的功能,在進入后臺的時候,應用還要做一些事情。例如,任何活躍的Bonjour服務應該被掛起,停止調用OpenGL ES函數(shù)。當進入后臺時應該執(zhí)行的操作的列表,參見Being a Responsible Background App。

后臺轉換周期

當用戶點擊Home鍵、按下休眠/喚醒按鈕、或者系統(tǒng)啟動其他應用,前臺的應用會轉換到非活躍狀態(tài),然后進入后臺狀態(tài)。這些轉換導致調用應用委托的applicationWillResignActive:和applicationDidEnterBackground:方法,如圖4-5所示。在從applicationDidEnterBackground:方法返回之后,大多數(shù)應用很快進入到掛起狀態(tài)。請求特定后臺任務(如播放音樂)或從系統(tǒng)請求額外運行時間的應用可以繼續(xù)運行一段時間。

圖4-5 從前臺進入后臺

準備應用快照

在應用委托方法applicationDidEnterBackground:返回不久,系統(tǒng)會得到一張應用視窗的快照。同樣,當應用被喚醒來執(zhí)行后臺任務的時候,系統(tǒng)可以可以得到一張新的快照,新快照反映了相關的改變。例如,當應用被喚醒來處理下載項目時,系統(tǒng)會得到新快照,以便能夠反映因為合并項目而導致的任何變化。系統(tǒng)在多任務UI中使用這些快照來展示應用的狀態(tài)。

如果在進入后臺之前你改變了視圖,你可以調用主視圖的snapshotViewAfterScreenUpdates:方法來強制執(zhí)行這些更改。在視圖上調用setNeedsDisplay方法對快照無效,因為在下一個繪圖周期之前快照已產生,因此可以防止任何改變被渲染。調用使用值為YES的snapshotViewAfterScreenUpdates:方法,立即更新快照使用的底層緩沖區(qū)。

減少內存占用

每個應用都應該在進入后臺之前盡可能多的釋放內存。系統(tǒng)會在內存中保留盡可能多的內存,但是當內存不足時,它會掛起應用以便回收內存。那些在后臺消耗大量內存的應用會被先終止。

實際上,應用一旦不需要某個對象時,就應該移除對該對象的強引用。移除強引用可以讓編譯器獲得釋放這些對象的能力,以便可以回收相應的內存。但是,如果你想緩存一些對象以提高性能,你可以在進入后臺之前保留它們。

一些應該盡可能移除強引用的對象:

  • 你創(chuàng)建的圖片對象。(一些返回圖片的UIImage 方法,它底層的圖片數(shù)據(jù)會被系統(tǒng)自動清除。更多信息,參見UIImage Class Reference的瀏覽討論。)
  • 可以從磁盤再次加載的媒體或數(shù)據(jù)文件。
  • 任何不再需要且創(chuàng)建方便的對象。

為了幫助減少應用對內存的占用,系統(tǒng)會在應用進入后臺前自動清除一些它代表應用分配的數(shù)據(jù)。

  • 系統(tǒng)清除所有Core Animation層的備份。此功能不會從內存移除應用的圖層對象,不會改變現(xiàn)有圖層屬性。它只是防止這些顯示在屏幕上的內容,在后臺時仍試圖作用于應用。
  • 移除任何對緩存圖片的系統(tǒng)引用。
  • 移除對其他系統(tǒng)管理的數(shù)據(jù)緩存的強引用,

(本節(jié)結束)

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容