"Return your app to its previous state after the system terminates it."
시스템 종료 후 앱을 이전 상태로 되돌립니다.
앱의 UI를 보존하는 것은 앱이 항상 작동하고 있는 착각을 유지하는 데 도움이 됩니다. iOS 기기에서 인터럽션은 빈번히 발생할 수 있고, 인터럽션이 길어지는 것은 시스템이 리소스 확보를 위해 앱을 종료시킬 수도 있게 합니다. 그러나 사용자는 앱이 종료되었는지 알 수 없고 앱애 변경된 상태임을 기대하지 않을 것입니다. 대신 사용자는 앱에서 빠져나왔을 때도 같은 상태로 있을 것임을 기대할 것입니다. 상태 보존 및 복원은 앱이 다시 launch 되었을 때 이전 상태로 되돌아가는 것을 보장해줍니다.
적합한 시점에 UIKit
은 앱의 뷰와 뷰 컨트롤러 상태를 디스크에 있는 암호화된 파일에 저장합니다. 앱이 종료되었다가 이후에 다시 launch 되면, UIKit
은 보존된 데이터로부터 뷰와 뷰 컨트롤러를 재구성합니다. 보존 및 복원 과정은 자동으로 초기화되지만, 이와 같은 과정을 지원하려면 몇 가지 특정 작업을 수행해야 합니다.
인터페이스 전체를 스토리보드에서 정의하는 경우 UIKit
은 뷰 컨트롤러를 재생성할 방법에 대해 알고 있습니다. 그리고 자동으로 이를 수행합니다. 스토리보드를 사용하지 않거나 뷰 컨트롤러의 생성 및 초기화를 더 제어하길 원한다면, 뷰 컨틀로러르 스스로 직접 생성할 수 있습니다.
상태 보존 및 복원에 대한 예시는 Restoring Your App’s State를 살펴보시기 바랍니다.
Restoring Your App’s State
https://developer.apple.com/documentation/uikit/uiscenedelegate/restoring_your_app_s_state
앱 딜리게이트의 application(_:shouldSaveApplicationState:)
, application(_:shouldRestoreApplicationState:)
메소드 구현을 통해 상태 보존 및 복원을 선택할 수 있습니다. 두 메소드는 관련 프로세스가 발생해야 하는지 여부를 나타내는 불리언 값을 반환하며, 대부분의 경우 단순하게 true
를 반환하면 됩니다. 그러나 앱의 인터페이스 복구가 적합하지 않은 경우에 대해서 false
를 반환할 수도 있습니다.
UIKit
이 application(_:shouldSaveApplicationState:)
메소드를 호출할 떄, true
를 반환하는 것과 더불어 데이터를 저장할 수도 있습니다. 복원 과정 동안 사용하길 의도한 데이터를 저장하게 될 것입니다. 예를 들어 Listing 1은 앱의 현재 버전 넘버를 저장하는 예시를 보여줍니다. 복원 시점에 application(_:shouldRestoreApplicationState:)
메소드가 아카이브에서 버전 넘버를 확인하고, 기대되는 버전과 일치하지 않는 경우 복원 발생을 막습니다.
Listing 1 Declaring support for state preservation and restoration
func application(_ application: UIApplication,
shouldSaveApplicationState coder: NSCoder) -> Bool {
// Save the current app version to the archive.
coder.encode(11.0, forKey: "MyAppVersion")
// Always save state information.
return true
}
func application(_ application: UIApplication,
shouldRestoreApplicationState coder: NSCoder) -> Bool {
// Restore the state only if the app version matches.
let version = coder.decodeFloat(forKey: "MyAppVersion")
if version == 11.0 {
return true
}
// Do not restore from old data.
return false
}
복원을 막는 경우에도 여전히 앱 딜리게이트의 application(_:didFinishLaunchingWithOptions:)
메소드에서 앱의 인터페이스를 설정할 수 있습니다.
복원 아이덴티파이어 할당을 통해 어떤 뷰 컨트롤러를 보존할 것인지에 대해서 UIKit
에게 명시적으로 알려줘야 합니다. 복원 아이덴티파이어는 코드 작성 혹은 인터페이스 빌더로 뷰 컨트롤러에 할당하는 고유한 스트링입니다. 뷰 컨트롤러 클래스의 이름은 보통 적합한 복원 아이덴티파이어이지만, 다른 스트링을 사용해도 됩니다. 스토리보드 파일에서 뷰 컨트롤러에 해당 스트링을 추가하거나 런타임에 뷰 컨트롤러의 restorationIdentifier
속성에 해당 스트링을 할당해야 합니다.
Figure 1 Specifying a restoration identifier in the storyboard
보존 시점에 UIKit
은 앱 윈도우의 루트 뷰 컨트롤러 보존을 시도합니다. 복원 아이덴티파이어를 갖는 각각의 루트 뷰 컨트롤러에서 UIKit
은 아카이브 속에 커스텀 데이터를 인코딩해야 함을 해당 뷰 컨트롤러에게 요청합니다. 컨테이너 뷰 컨트롤러는 커스텀 데이터의 일부로써 자식 뷰 컨트롤러에 레퍼런스를 인코딩할 수 있습니다. 만약 그렇게 하는 경우, 그리고 해당 뷰 컨트롤러가 복원 아이덴티파이어 역시 갖고 있는 경우, UIKit
은 자식 뷰 컨트롤러 및 자식 뷰 컨트롤러의 컨텐츠 보존을 시도합니다. 이 과정은 재귀적으로 계속되며, 모든 뷰 컨트롤러가 저장되거나 무시될 때까지 하나의 뷰 컨트롤러로부터 다음까지의 연결에 따라 계속합니다..
모든 뷰 컨트롤러에 복원 아이덴티파이어 할당이 필요하진 않습니다. 어떤 경우에 모든 뷰 컨트롤러의 보존을 원하지 않을 수도 있습니다. 예를 들어 앱이 일시적인 로그인 스크린을 표시하는 경우 스크린이 보존되지 않길 원할 것입니다. 대신 복원 시 표시 여부에 대해 결정하길 원할 것입니다. 이 경우 로그인 스크린 뷰 컨트롤러에 복원 아이덴티파이어를 할당하지 않아야 합니다.
어떤 것이 보존되는지에 대한 더 자세한 정보는 About the UI Preservation Process를 살펴보시기 바랍니다.
About the UI Preservation Process
https://developer.apple.com/documentation/uikit/view_controllers/preserving_your_app_s_ui_across_launches/about_the_ui_preservation_process
https://velog.io/@panther222128/About-the-UI-Preservation-Process
보존 과정이 진행되는 동안 UIKit
은 각각의 보존된 뷰 및 뷰 컨트롤러의 encodeRestorableState(with:)
메소드를 호출합니다. 뷰 혹은 뷰 컨트롤러의 현재 상태를 되돌리는 데 필요한 정보를 보존하기 위해 이 메소드를 사용하시기 바랍니다.
상태 보존은 앱 데이터를 디스크에 저장하는 것에 대한 대체재가 아닙니다. UIKit
은 재량에 다라 상태 보존 데이터를 버릴 수 있으며, 이는 앱을 기본값 상태로 되돌릴 수 있도록 해줍니다. 현재 선택된 테이블의 행과 같은 앱의 UI 상태에 대한 정보를 저장하기 위해 보존 프로세스를 사용해야 합니다. 해당 테이블에 포함된 데이터 저장을 위해 사용해서는 안 됩니다.
Listing 2는 first name과 last name을 수집하는 텍스트 필드를 갖는 뷰 컨트롤러의 예시를 보여주고 있습니다. 만약 텍스트 필드 중 한 가지가 저장되지 않은 값을 포함한다면, 메소드는 저장되지 않은 값과 어떤 텍스트 필드가 값을 포함하고 있는지에 대한 아이덴티파이어를 저장합니다. 이 경우 저장되지 않은 값은 앱의 영구 데이터의 부분이 아닙니다. 이는 필요한 경우에 따라 버려질 수 있는 일시적인 값입니다.
Listing 2 Encoding the state of a view controller
override func encodeRestorableState(with coder: NSCoder) {
super.encodeRestorableState(with: coder)
// Save the user ID so that we can load that user later.
coder.encode(userID, forKey: "UserID")
// Write out any temporary data if editing is in progress.
if firstNameField!.isFirstResponder {
coder.encode(firstNameField?.text, forKey: "EditedText")
coder.encode(Int32(1), forKey: "EditField")
}
else if lastNameField!.isFirstResponder {
coder.encode(lastNameField?.text, forKey: "EditedText")
coder.encode(Int32(2), forKey: "EditField")
}
else {
// No editing was in progress.
coder.encode(Int32(0), forKey: "EditField")
}
}
UIKit
이 앱의 뷰, 뷰 컨트롤러, 상태 정보를 어떻게 보존하는지에 대한 더 많은 정보는 About the UI Preservation Process를 살펴보시기 바랍니다.
About the UI Preservation Process
https://developer.apple.com/documentation/uikit/view_controllers/preserving_your_app_s_ui_across_launches/about_the_ui_preservation_process
https://velog.io/@panther222128/About-the-UI-Preservation-Process
만약 보존된 상태 정보가 앱 launch 시점에 사용 가능하다면, 시스템은 보존된 데이터를 사용해 앱의 인터페이스 복구를 시도합니다.
UIKit
은 앱 딜리게이트의 application(_:shouldRestoreApplicationState:)
메소드를 호출해서 복원이 진행되어야 하는지를 결정합니다.UIKit
은 뷰 컨트롤러를 재생성하기 위해서 앱의 스토리보드를 사용합니다.UIKit
은 각 뷰 컨트롤러가 갖는 상태 정보 복원을 위해 각 뷰 컨트롤러의 decodeRestorableState(with:)
메소드를 호출합니다.UIKit
은 초기에 스토리보드로부터 뷰 컨트롤러 및 뷰 컨트롤러의 뷰 모두를 로드합니다. 해당 객체들이 로드되고 초기화된 후, UIKit
은 상태 정보 복원을 시도합니다. 뷰 컨트롤러를 이전 상태로 되돌리기 위해 decodeRestorableState(with:)
메소드를 사용하시기 바랍니다.
Listing 3은 Listing 2에서 인코딩 했었던 상태를 디코딩하는 메소드에 대해 보여주고 있습니다. 이 메소드는 보존된 사용자 ID로부터 뷰 컨트롤러의 데이터를 복원합니다. 텍스트 필드가 편집되고 있었다면, 이 메소드는 진행중이었던 값을 복원하고, 해당 텍스트 필드에 대한 키보드를 표시할 수 있도록 상응하는 텍스트 필드를 첫 번째 리스폰더로 만듭니다.
Listing 3 Decoding the
override func decodeRestorableState(with coder: NSCoder) {
super.decodeRestorableState(with: coder)
// Restore the first name and last name from the user ID
let identifier = coder.decodeObject(forKey: "UserID") as! String
setUserID(identifier: identifier)
// Restore an in-progress values that was not saved
let activeField = coder.decodeInteger(forKey: "EditField")
let editedText = coder.decodeObject(forKey: "EditedText") as!
String?
switch activeField {
case 1:
firstNameField?.text = editedText
firstNameField?.becomeFirstResponder()
break
case 2:
lastNameField?.text = editedText
lastNameField?.becomeFirstResponder()
break
default:
break // Do nothing.
}
}
스토리보드에서 뷰 컨트롤러를 정의하는 것은 상태 복원을 관리하는 가장 쉬운 방법이지만 유일한 방법은 아닙니다. 다른 방법을 통해 뷰 컨트롤러를 재생성하는 것에 대한 더 많은 정보는 About the UI Restoration Process를 살펴보시기 바랍니다.
About the UI Restoration Process
https://developer.apple.com/documentation/uikit/view_controllers/preserving_your_app_s_ui_across_launches/about_the_ui_restoration_process
https://velog.io/@panther222128/About-the-UI-Restoration-Process
UIKit 상태 보존 프로세스를 커스터마이징 하는 방법에 대해 알아봅니다.
https://developer.apple.com/documentation/uikit/view_controllers/preserving_your_app_s_ui_across_launches/about_the_ui_preservation_process
https://velog.io/@panther222128/About-the-UI-Preservation-Process
UIKit 상태 복원 과정을 커스터마이징 하는 방법에 대해 알아봅니다.
https://developer.apple.com/documentation/uikit/view_controllers/preserving_your_app_s_ui_across_launches/about_the_ui_restoration_process
https://velog.io/@panther222128/About-the-UI-Restoration-Process