UIScene Lifecycle に対応するには
対応に使うクラスは2つ。
- UIWindowScene
- UISceneSession
UIWindowScene
UIKit内のUIの構造はこう。
ここに UIWindowScene がこのように入り込む。
ユーザーがドラッグ&ドロップをしたとき、アプリのUIから新しいUIを作ることを要求する場面(Scene)で、システムはUIをスクリーンに表示するように要求する。
シーンがバックグラウンドになってインタラクティブでなくなると、システムがその状況を把握して不要になったシーンを削除する。
シーンが削除されていても、ユーザーはスイッチャーにまだ残っていると思うもの。アプリはユーザーがバックグラウンドにしたシーンの情報を保持しておく必要がある。
そこで活躍するのが UISceneSession 。
UISceneSession
UISceneSession はユーザーが最後に操作したUIWindowSceneのインターフェースの情報を保持している。
Expose で表示されるのは同一のアプリである場合ウィンドウが表示されているとユーザーは認識するが、開発者は SceneSession が表示されていると認識しよう。
これは重要。なぜならユーザーが目にしているのはSceneSessionのスナップショットであって、実際にロードされた画面ではないからだ。
ウィンドウは現れたり消えたりするが、セッションは存在していてウィンドウ生成に使用される。
SceneSession を管理するAPIが複数ある。
新しいセッションを作る
requestSceneSessionActivation(_:userActivity:options:errorHandler)
既に存在しているSceneを更新する
requestSceneSessionRefresh(_:)
Sceneを閉じる
requestSceneSessionDestruction(_:options:errorHandler:)
UIWindowScene.DestructionRequestOptions()
の .windowDismissalAnimation
でアニメーションを指定できる。
状態のリストア
class UISceneSession { var stateRestorationUserActivity: NSUserActivity // システムによって作られた文字列、同じシーンに同じ識別子が使われる var persistentIdentifier: String { get } // UserDefaultsと同じようなデータを保存できる userInfo: [String: AnyHashable] }
デバッグについて
デバッグするポイントは2つ。
- アプリケーションを使ってみること
- 情報の共有方法を見直す(Key-Value Observing を使うとか)
Case1. ドキュメントをマルチウィンドウで2つ開いたが保存したら両方とも同じ内容になってしまった
ドキュメントデータの保存情報にセッションIDを持たせる。
Case.2 アプリの設定変更したのに片方のSceneにしか反映されない
Key-Value Observing を使って設定情報を購読する。(RxSwift, Combine でも代用できる)
Key-Value Observing を使う場合は以下のように .initial オプションを渡す。これを渡すことにより購読されたときに1回 changeHandler が実装される。