當應用進入前臺的時候該做什么
回到前臺的過程是應用重啟一些任務的機會,這些任務是在應用進入后臺的時候被停止的。圖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é)結束)