UIApplicationDelegateメソッド `application(_:configurationForConnecting:options:)`が確実に呼び出されないのはなぜですか

Aug 21 2020

問題:

AppDelegateメソッドに関して予期しない動作が見られますapplication(_:configurationForConnecting:options:)

ドキュメントには次のように記載されています。

UIKitは、新しいシーンを作成する直前にこのメソッドを呼び出します。

これは、アプリが起動されるたびに当てはまると思います。
このメソッドは、アプリを初めて起動したときに実際に呼び出されますが、それ以降のすべての起動では呼び出されません

再現:

再現する非常に単純なテストケースがあります。

  • Xcode12>新しいプロジェクトの作成> iOS>アプリ(UIKit / Storyboard)
  • 次のAppDelegateように、メソッドにデバッグステートメントを追加します。
      // from Apple's sample project:
      func application(_ application: UIApplication, configurationForConnecting connectingSceneSession: UISceneSession, options: UIScene.ConnectionOptions) -> UISceneConfiguration {
          // Called when a new scene session is being created.
          // Use this method to select a configuration to create the new scene with.
          print("I was called!").  // <--- debugging statement
          return UISceneConfiguration(name: "Default Configuration", sessionRole: connectingSceneSession.role)
      }
    
  • アプリを実行>「私は呼ばれました!」コンソールに印刷されます
  • アプリを再度実行します>何も印刷されません。

質問:

application(_:configurationForConnecting:options:)2回目の起動時に呼び出されないのはなぜですか?
(それは予想される動作ですか、はいの場合はなぜですか/それはAppleによるバグですか?)

回答

3 Adrian Oct 21 2020 at 05:10

これは予想される動作のようであり、何が起こっているのかを理解すれば意味がありますが、文書化されていません。私はちょうどそれの底に到達するためにかなりトラウマ的な時間を過ごしました。ああ、アップル。

知っておくべき重要なことは、アプリを再起動すると、前回の実行のウィンドウが復元されることです。

(アプリには複数の種類のウィンドウがあり、それぞれがシーン構成で表されていることを覚えておくと役立ちます。そのため、最初にこのデリゲートメソッドを実装する場合があります。)

ケース1:アプリが初めてリリースされた

アプリはウィンドウにどのタイプのシーンを配置するかを知らず、それapplication(_:configurationForConnecting:options:)を見つけるために呼び出します。これまでのところ、物事は私たちが期待する通りです。(このデリゲートメソッドを実装しない場合は、Info.plistシーンマニフェストの最初の適切なエントリにフォールバックします(ある場合)。)

ケース2:新しいウィンドウが作成されました(複数のウィンドウをサポートするアプリの場合)

(iPadのドックアイコンをドラッグするなど)。アプリもこのウィンドウに何を入れるべきかわかりません。ケース1と同じ。

ケース3:アプリが再起動されました

OSがウィンドウを復元しようとしています。これを行うために、前回開いたウィンドウのシーン構成を記憶しています。驚き!ウィンドウに配置するシーンを認識しており、アプリのデリゲートに問い合わせることはありません。先に進み、記憶された構成を使用してシーンを作成します。

アプリの起動時に作成されるウィンドウの観点から考える貧しい開発者にとって、これは混乱を招きます。しかし、ウィンドウが起動時に復元され、作成されないという観点から考えると、ウィンドウが1つしかない場合でも、それは理にかなっています。


ここで、ウィンドウが忘れられ、次の起動時にデリゲートメソッドが呼び出されるようにリセットする場合は、次のようにします。

  • iOSの場合は、アプリを削除します
  • Catalystの場合、アプリのコンテナを削除します

注1: Catalystでは、再起動時に最初のウィンドウのみが復元されるようですが、それ以外の動作は上記と同じです。 これが真実ではないことを今観察しました。おそらくそれは一貫性がありません。

注2:とを使用して、ウィンドウのタイプだけでなく、ウィンドウのコンテンツを復元することもできますが、それは別の話です。UIWindowSceneDelegateUISceneSession.stateRestorationActivity