为什么不可靠地调用 UIApplicationDelegate 方法`application(_:configurationForConnecting:options:)`

de.*_*de. 5 ios appdelegate swift uiscenedelegate xcode12

问题:

我发现有关 AppDelegate 方法的一些意外行为application(_:configurationForConnecting:options:)

该文件指出:

UIKit 在创建新场景前不久调用此方法。

我希望每次启动应用程序时都是这种情况。
当我第一次启动我的应用程序时确实会调用该方法,但是对于所有后续启动,它不是.

复制:

我有一个非常简单的测试用例来重现:

  • Xcode 12 > 创建新项目 > iOS > 应用程序(UIKit/故事板)
  • 在方法中添加调试语句,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)
      }
    
    Run Code Online (Sandbox Code Playgroud)
  • 运行应用程序 > “我被叫了!” 在控制台打印
  • 再次运行应用程序 > 没有打印任何内容。

题:

为什么application(_:configurationForConnecting:options:)在第二次发射时没有被调用?
(这是预期的行为,如果是,为什么/这是 Apple 的错误)

Adr*_*ian 11

这似乎是预期的行为,并且一旦您了解正在发生的事情就有意义,但没有记录在案。我刚刚花了一些相当痛苦的时间来了解它的底部。哦,苹果。

要知道的关键是,当您重新启动应用程序时,会恢复上次运行的窗口。

(记住一个应用程序可以有多种类型的窗口——每一种都由一个场景配置表示——这也是你可能首先实现这个委托方法的原因。)

案例 1:有史以来第一次启动应用

应用程序不知道在窗口中放置什么类型的场景,并调用application(_:configurationForConnecting:options:)查找。到目前为止,事情正如我们所料。(如果你没有实现这个委托方法,它只会回退到你Info.plist的场景清单中的第一个合适的条目,如果它有的话。)

案例 2:创建新窗口(适用于支持多窗口的应用)

(例如通过拖动 iPad 上的停靠栏图标)。该应用程序也不知道在此窗口中放置什么。与案例1相同。

案例 3:应用重新启动

操作系统想要恢复您的 Windows。为此,它记住了您上次打开的窗口的场景配置。惊喜!它知道在窗口中放置哪些场景,并且不会询问您的应用程序委托。它只是继续使用记住的配置创建场景。

对于那些在应用程序启动时创建一个窗口的可怜的开发人员来说,这是令人困惑的。但是,如果您认为 Windows 在启动时被恢复,而不是被创建——即使只有一个——它开始变得有意义。


现在,如果您想重置一些东西以便忘记您的窗口并在下次启动时调用您的委托方法:

  • 对于 iOS,删除应用程序
  • 对于 Catalyst,删除应用程序的容器

注 1: 在 Catalyst 中,似乎只有在重新启动时才恢复第一个窗口,但其他行为与上述相同。现在观察到这不是真的。也许是不一致的。

注意 2:您还可以使用和恢复窗口的内容,而不仅仅是它们的类型,但那是另一回事了。UIWindowSceneDelegateUISceneSession.stateRestorationActivity