Почему метод UIApplicationDelegate `application (_: configurationForConnecting: options:)` не вызывается надежно
Проблема:
Я обнаружил неожиданное поведение метода AppDelegate application(_:configurationForConnecting:options:)
.
В документации указано:
UIKit вызывает этот метод незадолго до создания новой сцены.
Я ожидал, что это будет происходить каждый раз при запуске приложения.
Метод действительно вызывается, когда я запускаю свое приложение в первый раз, однако при всех последующих запусках это не так .
Воспроизвести:
У меня есть очень простой тестовый пример для воспроизведения:
- Xcode 12> Создать новый проект> 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:)
не вызывается на второй запуск?
(Это ожидаемое поведение, если да, почему / Это ошибка Apple)
Ответы
Это кажется ожидаемым поведением и имеет смысл, если вы понимаете, что происходит, но это не задокументировано. Я только что потратил довольно болезненное время на то, чтобы разобраться в этом. О, Apple.
Главное, что нужно знать, - это то, что при перезапуске приложения окна из предыдущего запуска восстанавливаются.
(Это также помогает помнить, что приложение может иметь несколько типов окон - каждый из которых представлен конфигурацией сцены - поэтому вы можете в первую очередь реализовать этот метод делегата.)
Случай 1: приложение запущено впервые
Приложение не знает, какую сцену поместить в окно, и звонит, application(_:configurationForConnecting:options:)
чтобы узнать. Пока все так, как мы ожидали. (Если вы не реализуете этот метод делегата, он просто вернется к первой подходящей записи в Info.plist
манифесте вашей сцены, если она есть.)
Случай 2: создано новое окно (для приложений, поддерживающих несколько окон)
(например, перетащив значок док-станции на iPad). Приложение также не знает, что поместить в это окно. То же, что и в случае 1.
Случай 3: приложение перезапущено
ОС хочет восстановить ваши окна. Для этого он запомнил конфигурации сцен окон, которые вы открывали в прошлый раз. Сюрприз! Он знает, какие сцены помещать в окна, и не спрашивает делегата вашего приложения. Он просто идет вперед и создает сцены, используя запомненные конфигурации.
Это сбивает с толку плохого разработчика, который думает о том, что окно создается при запуске приложения. Но если вы думаете о том, что окна восстанавливаются при запуске, а не создаются - даже когда есть только одно - это начинает иметь смысл.
Теперь, если вы хотите сбросить настройки, чтобы ваши окна были забыты, а ваш метод делегата вызывался при следующем запуске:
- для iOS удалите приложение
- для Catalyst удалите контейнер приложения
Примечание 1:
в Catalyst кажется, что при перезапуске восстанавливается только первое окно, но в остальном поведение такое же, как указано выше.
Теперь заметили, что это неправда. Возможно, это непоследовательно.
Примечание 2: вы также можете восстановить содержимое ваших окон , а не только их тип , используя UIWindowSceneDelegate
и UISceneSession.stateRestorationActivity
, но это уже другая история.