Методы делегата приложения не вызываются в iOS 13
Я использую Xcode 11 и создаю приложение для iOS 13. В новом проекте, который я создал в Xcode, я добавил методы делегата для UIApplicationDelegate. В новом шаблоне проекта "Single View App" их не было. Проблема в том, что ни один из методов делегата, кроме -application:didFinishLaunchingWithOptions:
звонят. Вот мой делегат приложения:
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSLog(@"application:didFinishLaunchingWithOptions:");
return YES;
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
NSLog(@"applicationDidEnterBackground:");
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
NSLog(@"applicationWillEnterForeground:");
}
#pragma mark - UISceneSession lifecycle
- (UISceneConfiguration *)application:(UIApplication *)application configurationForConnectingSceneSession:(UISceneSession *)connectingSceneSession options:(UISceneConnectionOptions *)options {
return [[UISceneConfiguration alloc] initWithName:@"Default Configuration" sessionRole:connectingSceneSession.role];
}
- (void)application:(UIApplication *)application didDiscardSceneSessions:(NSSet<UISceneSession *> *)sceneSessions {
}
@end
1 ответ
В iOS 13 появился новый способ отправки событий жизненного цикла приложения. Вместо того, чтобы проходить через UIApplicationDelegate
они проходят через UIWindowSceneDelegate
который является UISceneDelegate
суб-протокол. UISceneDelegate
методы перечислены в документации API.
Это все для поддержки нескольких окон в iOS 13. Более подробная информация содержится в сеансе 212 WWDC 2019 " Представление нескольких окон на iPad ". Техническая информация начинается около 14:30 и представлена человеком с очень блестящими высокими вершинами.
Если у вас есть " Манифест сцены приложения " в вашем Info.plist, и ваш представитель приложения имеет configurationForConnectingSceneSession
метод UIApplication
не будет отправлять фоновые и передние сообщения жизненного цикла делегату приложения (applicationDidBecomeActive
, applicationWillResignActive
, applicationDidEnterBackground
, applicationWillEnterForeground
). Делегат приложения все равно получит willFinishLaunchingWithOptions:
а также didFinishLaunchingWithOptions:
,
Если вы хотите вернуть старое поведение, вам нужно
- Удалите запись "Манифест сцены приложения" из Info.plist приложения.
- Прокомментируйте или удалите
application:configurationForConnectingSceneSession:options:
метод (или Свифтapplication(_:configurationForConnecting:options:)
функция) - Добавьте свойство окна обратно вашему делегату приложения (
@property (strong, nonatomic) UIWindow *window;
)
Кроме того, откройте файл SceneDelegate, созданный XCode, и используйте там новые методы жизненного цикла:
- (void)sceneDidBecomeActive:(UIScene *)scene {
}
- (void)sceneWillResignActive:(UIScene *)scene {
}
... etc
Можно использовать новый UIScene
вещи жизненного цикла без принятия поддержки нескольких окон, установив "Включить несколько окон" ("UIApplicationSupportsMultipleScenes") на "НЕТ" в Info.plist (это значение по умолчанию для новых проектов). Таким образом, вы можете начать применять новый API более мелкими шагами.
Вы можете видеть, что имена методов делегата сцены близко совпадают с именами делегатов приложения. Одна непонятная вещь заключается в том, что методы делегата приложения не являются устаревшими, поэтому вы не получите предупреждение, если у вас есть и делегат приложения, и методы делегата сцены, но будет вызываться только один.
Другие вещи, которые UISceneDelegate
принимает на себя действия пользователя (continueUserActivity:
и т. д.), государственное восстановление (stateRestorationActivityForScene:
и т. д.), вопросы в строке состояния и открытые URL. (Я не уверен, заменяют ли они методы делегата приложения). Он также имеет аналогичные уведомления для событий жизненного цикла.
С сессии WWDC, некоторые изображения для вас:
Эквиваленты функций для Swift:
Классовые обязанности:
Жизненный цикл приложения и сцены - это не одно и то же!
На мой взгляд, отключение вызовов методов изменения состояния приложения (а также отправка уведомлений об изменении состояния приложения при изменении состояния каждой сцены) является ошибкой, хотя было понятное намерение заставить программистов адаптироваться к жизненному циклу новых сцен.
Вот шаблон делегата сцены, восстанавливающий ожидаемые вызовы методов изменения состояния приложения делегата приложения:
@available(iOS 13.0, *)
class SceneDelegate: UIResponder, UIWindowSceneDelegate {
func sceneWillResignActive(_ scene: UIScene) {
if !UIApplication.shared.connectedScenes.contains(where: { $0.activationState == .foregroundActive && $0 != scene }) {
UIApplication.shared.delegate?.applicationWillResignActive?(.shared)
}
}
func sceneDidEnterBackground(_ scene: UIScene) {
if !UIApplication.shared.connectedScenes.contains(where: { $0.activationState == .foregroundActive || $0.activationState == .foregroundInactive }) {
UIApplication.shared.delegate?.applicationDidEnterBackground?(.shared)
}
}
func sceneWillEnterForeground(_ scene: UIScene) {
if !UIApplication.shared.connectedScenes.contains(where: { $0.activationState == .foregroundActive || $0.activationState == .foregroundInactive }) {
UIApplication.shared.delegate?.applicationWillEnterForeground?(.shared)
}
}
func sceneDidBecomeActive(_ scene: UIScene) {
if !UIApplication.shared.connectedScenes.contains(where: { $0.activationState == .foregroundActive && $0 != scene }) {
UIApplication.shared.delegate?.applicationDidBecomeActive?(.shared)
}
}
}
Эта ветка мне помогла:
Контроллер представления отвечает на уведомления делегата приложения в iOS 12, но не в iOS 13
Цель C:
if (@available(iOS 13.0, *)) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(appWillResignActive:)
name:UISceneWillDeactivateNotification object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(appDidBecomeActive:)
name:UISceneDidActivateNotification object:nil];
}
else {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(appWillResignActive:)
name:UIApplicationWillResignActiveNotification object:nil];
[[NSNotificationCenter defaultCenter]addObserver:self
selector:@selector(appDidBecomeActive:)
name:UIApplicationDidBecomeActiveNotification
object:nil];
}