[譯] 狀態恢復入門教程

淚已無痕發表於2019-01-07

在這篇狀態恢復教程中,我們將瞭解如何使用 Apple 的狀態恢復介面來提升使用者的應用體驗。

注意:Xcode 7.3、iOS 9.3 和 Swift 2.2 已於 2016-04-03 更新。

在 iOS 系統中,狀態恢復機制是一個經常被忽略的特性,當使用者再次開啟 app 的時候,它能夠精確的恢復到退出之前的狀態 - 而不用關心發生了什麼。

某些時候,作業系統可能需要從記憶體中刪除你的應用;這可能會嚴重中斷使用者的工作流。你的使用者再也不必擔心因為切換到另一個應用而影響到工作的事情了。這就是狀態恢復機制所起到的作用。

在這篇恢復教程中,你將更新現有應用以新增保留和恢復功能,並在其工作流可能被中斷的情況下提升使用者體驗。

入門

下載本教程的 入門專案。該應用名為「Pet Finder」;對於那些碰巧在尋找毛茸茸貓科動物陪伴的人來說,這是一款方便的應用。

執行該應用;你將會看到一張關於貓的圖片,這代表你有機會可以領養它:

Pet Finder

向右滑動即可與新的毛茸茸的朋友配對;向左滑動表示你想要繼續傳遞這個絨毛球小貓。你可以從匹配選項卡欄中檢視當前所有的匹配列表:

Matches

點選來檢視所選中朋友的更多詳細資訊:

Details

你甚至可以編輯你新朋友的名字(或年齡,如果你是在扭曲事實):

Edit

你希望當你離開該應用然後返回時,你會被帶回到上一次檢視的同一個毛茸茸朋友。但真的是這樣嗎?要知道答案的唯一方法就是測試它。

狀態恢復測試

執行應用,向右滑動至少一隻貓,檢視你的匹配項,然後選擇一隻貓並檢視他或她的詳細資訊。按組合鍵 Cmd + Shift + H 返回主頁面。如果存在任何邏輯上的狀態,它都會被儲存並且都將在此時執行。

接下來,通過 Xcode 停止應用:

Stop App

當使用者手動殺死應用或狀態恢復失敗時,狀態恢復框架將丟棄任何狀態資訊。之所以存在這些檢查,以避免你的應用不會陷入無線迴圈的錯誤狀態以及恢復崩潰。謝謝,Apple!:]

注意:你無法通過應用切換器自行終止應用,否則狀態恢復將無法正常工作。

再次啟動應用;你將回到主螢幕,而不是寵物詳情檢視。看起來你需要自己新增一些狀態恢復邏輯。

實現狀態恢復

設定狀態恢復的第一步是在你的應用代理中啟用它,開啟 AppDelegate.swift 並新增以下程式碼:

func application(application: UIApplication, shouldSaveApplicationState coder: NSCoder) -> Bool {
  return true
}

func application(application: UIApplication, shouldRestoreApplicationState coder: NSCoder) -> Bool {
  return true
}
複製程式碼

應用代理中有五個方法來管理狀態恢復。返回 trueapplication(_:shouldSaveApplicationState:),告訴系統儲存 view 的狀態,並在應用處於後臺執行狀態時檢視 view controller。返回 trueapplication(_:shouldRestoreApplicationState:),告訴系統在應用重新啟動時嘗試恢復原始狀態。

你可以在某些情況下讓這些代理方法返回 false,例如在測試時或使用者執行的應用的舊版本無法恢復時。

構建並執行你的應用,然後導航到貓的詳情頁。按住組合鍵 Cmd + Shift + H 讓你的應用進入後臺,然後通過 Xcode 停止應用。你將看到以下內容:

Pet Finder

confused

與你之前看到的完全相同!只選擇進行狀態恢復還不夠。雖然你已在應用中啟用了儲存和恢復,但 view controller 尚未參與。要解決這個問題,你需要為每個場景提供一個恢復識別符號

設定恢復識別符號

恢復識別符號只是一個 view 和 view controller 的字串屬性,UIKit 使用它來將這些物件恢復到之前的狀態。它存在一個 UIKit 與你希望保留的物件通訊的值。只要這些屬性的值是唯一的,它們的實際內容並不重要。

開啟 Main.storyboard,你將看到一個 tab bar controller、一個 navigation controller 和三個自定義 view controller:

cinder_storyboard

恢復識別符號可以在程式碼中或在 Interface Builder 中設定。簡單起見,在本教程中你將在 Interface Builder 中進行設定。你可以進入併為每一個 view controller 設定一個唯一的名稱,但 Interface Builder 有一個 Use Storyboard ID 的快捷選項,它允許你將 Storyboard ID 用於恢復識別符號。

Main.storyboard 中,單擊 tab bar controller 並開啟 Identity Inspector。啟用 Use Storyboard ID 選項,如下所示:

Use Storyboard ID

這樣會把 view controller 行存檔記錄,並且在狀態恢復過程中進行還原。

對 navigation controller 和其它三個 view controller 重複此過程。確保你已經為每個 view controller 選中了 Use Storyboard ID。否則你的應用可能無法正常恢復其狀態。

請注意,所有 controller 都已經具有 Storyboard ID,並且該核取方塊僅使用已作為 Storyboard ID 的相同字串。如果你未使用 Storyboard ID,你需要手動輸入一個唯一的 Storyboard ID

恢復識別符號彙集在一起,通過應用中任何 view controller 的唯一路徑形成恢復路徑;它與 API 中的 URI 類似,其中唯一路徑標識每個資源的唯一路徑。

比如,以下路徑代表 MatchedPetsCollectionViewController

RootTabBarController/NavigationController/MatchedPetsCollectionViewController

通過這些設定,應用將記住你停止使用時的 view controller(大多數情況下),並且任何 UIKit view 都將保留其先前的狀態。

構建並執行你的應用;返回寵物詳情頁測試恢復流程。暫停和恢復應用後,你應該看到以下內容:

No Data

雖然系統恢復了正確的 view controller,但它似乎缺少填充 view 所需的貓物件。如何恢復 view controller 及其所需的物件呢?

UIStateRestoring 協議

在實現狀態恢復方面,UIKit 為你做了很多工作,但是你的應用需要負責自行處理一些事情:

  1. 告訴 UIKit 它想參與狀態恢復,就是你在應用代理中所做的那些。
  2. 告訴 UIKit 應該保留和恢復哪些 view controller 和 view。你通過為 view controller 分配恢復識別符號來解決此問題。
  3. 編碼和解碼任何需要重建 view controller 之前狀態的相關資料。你還沒有這樣做,但這是 UIStateRestoring 協議需要解決的問題。

每個具有恢復識別符號的 view controller 都將在儲存應用時接收 UIStateRestoring 協議對 encodeRestorableStateWithCoder(_:) 的呼叫。另外,view controller 將在應用恢復時接收 decodeRestorableStateWithCoder(_:) 的呼叫。

要完成恢復流程,你需要新增對 view controller 進行編碼和解碼的邏輯。雖然該過程可能是最耗時的,但概念相對簡單。你通常會編寫一個擴充套件來增加協議的一致性,但是 UIKit 會自動關注冊 view controller 以符合 UIStateRestoring - 你只需要覆蓋適當的方法。

開啟 PetDetailsViewController.swift,並在類的末尾新增以下程式碼:

override func encodeRestorableStateWithCoder(coder: NSCoder) {
  //1
  if let petId = petId {
    coder.encodeInteger(petId, forKey: "petId")
  }

  //2
  super.encodeRestorableStateWithCoder(coder)
}
複製程式碼

以下是上述程式碼要做的事:

  1. 如果當前貓物件存在 ID,使用提供的編碼器進行儲存以便稍後檢索。
  2. 確保呼叫 super 以便繼承的狀態恢復功能的其它部分能夠按照預期發生。

通過少量的修改,現在你的應用可以儲存當前貓的資訊。但請注意,你實際上並未儲存貓的模型物件,而是稍後可用於獲取貓物件的 ID,當你儲存通過 MatchedPetsCollectionViewController 選擇的貓時,可以使用相同的概念。

Apple 非常清楚,狀態恢復用於存檔建立 view 層次結構所需並將應用恢復到其原始狀態的資訊。每當應用進入後臺時,使用提供的編碼器來儲存和恢復簡單模型資料是很誘人的,但是隻要狀態恢復失敗或使用者殺死應用,iOS 將會丟棄所有存檔資料。由於你的使用者每次重新啟動應用時都不會非常樂意回到起始頁,所以最好遵循 Apple 的建議並僅使用此策略儲存狀態恢復。

現在你已經在 PetDetailsViewController.swift 中實現了編碼,你可以在下面新增相應的解碼方法:

override func decodeRestorableStateWithCoder(coder: NSCoder) {
  petId = coder.decodeIntegerForKey("petId")

  super.decodeRestorableStateWithCoder(coder)
}
複製程式碼

解密 ID 並將其設定回 view controller 的 petId 屬性。

一旦解碼了 view controller 的物件,該 UIStateRestoring 協議就會提供 applicationFinishedRestoringState() 的其他配置步驟。

PetDetailsViewController.swift 中新增以下程式碼:

override func applicationFinishedRestoringState() {
  guard let petId = petId else { return }
  currentPet = MatchedPetsManager.sharedManager.petForId(petId)
}
複製程式碼

上面是基於解碼後的寵物 ID 設定當前寵物,並完成 view controller 的恢復。當然,你可以在 decodeRestorableStateWithCoder(_:) 執行此操作,但最好保持邏輯分離,因為當它們全部捆綁在一起時它將變得笨拙。

構建並執行你的應用;導航到寵物的詳情頁並讓應用置於後臺,然後通過 Xcode 殺死該應用以觸發儲存序列。重啟應用並驗證你的毛茸茸玩具是否按預期顯示:

Details

你已經學習瞭如何恢復通過 storyboard 建立的 view controller。但你在程式碼中建立的 view controller 應該如何處理呢?要在執行時恢復基於 storyboard 建立的 view controller,UIKit 要做的是在 main storyboard 中找到它們。幸運的是,恢復基於程式碼建立的 view controller 幾乎一樣容易。

恢復基於程式碼建立的 view controller

檢視控制器 PetEditViewController 完全由程式碼建立;它用於編輯貓的名字和年齡。你將使用它來學習如何恢復基於程式碼建立的 view controller。

構建並執行你的應用;導航到貓的詳情頁,然後點選編輯。修改貓的名字,但不儲存你的更改,如下所示:

Edit

現在將應用置於後臺並通過 Xcode 殺死它以觸發儲存序列。重啟應用,iOS 將返回寵詳情頁而不是編輯頁:

Details

正如你在 Interface Builder 中構建的 view controller 所做的那樣,你需要為 view controller 提供恢復 ID,並新增 UIStateRestoring 協議中的編碼和解碼方法以便正確恢復狀態。

檢視 PetEditViewController.swift;你會注意到編碼和解碼的方法已經存在。邏輯類似於你在上一節中實現的編碼和解碼方法,但它還具有一些額外的屬性。

手動分配恢復識別符號是一個簡單的過程。在 viewDidLoad() 中呼叫 super 後立即新增以下內容:

restorationIdentifier = "PetEditViewController"
複製程式碼

這會為 restorationIdentifier 檢視控制器分配唯一 ID。

在狀態恢復過程中,UIKit 需要知道從何處獲得 view controller 引用。在你設定 restorationIdentifier 的下面新增以下程式碼:

restorationClass = PetEditViewController.self
複製程式碼

這將設定 PetEditViewController 為負責例項化 view controller 的恢復類。恢復類必須採用 UIViewControllerRestoration 協議並實現所需的恢復方法。為此,將以下擴充套件程式碼新增到 PetEditViewController.swift 的末尾:

extension PetEditViewController: UIViewControllerRestoration {
  static func viewControllerWithRestorationIdentifierPath(identifierComponents: [AnyObject],
      coder: NSCoder) -> UIViewController? {
    let vc = PetEditViewController()
    return vc
  }
}
複製程式碼

這實現了返回類例項所需的 UIViewControllerRestoration 協議方法。現在 UIKit 有了它正在尋找的物件的副本,iOS 可以呼叫編碼和解碼方法並恢復狀態。

構建並執行你的應用;導航到貓的編輯頁。像之前一樣更改貓的名字,但不儲存更改,然後將應用置於後臺並通過 Xcode 將其刪除。重啟你的應用,並驗證你所做的所有工作,為你的毛茸茸朋友提出一個偉大的獨特名稱並非都是徒勞的!

Edit

接下來去哪兒?

你可以 在此處現在已完成的專案。狀態恢復框架是任何 iOS 開發人員工具包中非常有用的工具;你現在可以將基本恢復程式碼新增到任何應用,並以此提高你的使用者體驗。

有關使用該框架可能實現的更多資訊,請檢視 2012 年2013 年的 WWDC 視訊。2013年的簡報特別有用,因為它涵蓋了 iOS 7 中引入的恢復概念,比如用於儲存和恢復任意物件的 UIObjectRestoration 和在需求更復雜的應用中恢復表和集合檢視的 UIDataSourceModelAssociation

如果你對本教程有任何疑問或建議,請加入以下論壇討論!

如果發現譯文存在錯誤或其他需要改進的地方,歡迎到 掘金翻譯計劃 對譯文進行修改並 PR,也可獲得相應獎勵積分。文章開頭的 本文永久連結 即為本文在 GitHub 上的 MarkDown 連結。


掘金翻譯計劃 是一個翻譯優質網際網路技術文章的社群,文章來源為 掘金 上的英文分享文章。內容覆蓋 AndroidiOS前端後端區塊鏈產品設計人工智慧等領域,想要檢視更多優質譯文請持續關注 掘金翻譯計劃官方微博知乎專欄

相關文章