在iOS 13中,App delegate方法没有被调用

79

我正在使用Xcode 11并为iOS 13构建应用程序。在Xcode中创建的新项目中,一些UIApplication委托方法丢失了,因此我将它们添加回应用程序委托文件中。"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
3个回答

197

iOS 13有一种新的发送应用程序生命周期事件的方法。它们不再通过UIApplicationDelegate传递,而是通过UIWindowSceneDelegate发送,这是一个UISceneDelegate子协议。 UISceneDelegate具有重要的委托方法。

此更改支持iOS 13中的多个窗口。在WWDC 2019会话212“介绍iPad上的多个窗口”中有更多信息。技术信息从大约14:30开始,由一位穿着非常闪亮的高帮鞋的男士演示。较短的会话258为多个窗口构建您的应用程序还介绍了发生了什么变化。

以下是其工作原理:如果在Info.plist中有一个“应用场景清单”,并且您的应用程序委托具有configurationForConnectingSceneSession方法,则UIApplication将不会向您的应用程序委托发送后台和前台生命周期消息。这意味着这些方法中的代码将不会运行:

  • applicationDidBecomeActive
  • applicationWillResignActive
  • applicationDidEnterBackground
  • applicationWillEnterForeground

应用程序委托仍将接收willFinishLaunchingWithOptions:didFinishLaunchingWithOptions:方法调用,因此这些方法中的任何代码都将像以前一样工作。

如果要恢复旧行为,则需要执行以下操作:

  1. 从应用程序的Info.plist中删除“应用场景清单”条目
  2. 注释或删除application:configurationForConnectingSceneSession:options:方法(或Swift的application(_:configurationForConnecting:options:)函数)
  3. 将窗口属性添加回您的应用程序委托(@property (strong, nonatomic) UIWindow *window;)

或者,打开Xcode创建的SceneDelegate文件,并在其中使用新的生命周期方法:

- (void)sceneDidBecomeActive:(UIScene *)scene {
}
- (void)sceneWillResignActive:(UIScene *)scene {
}
... etc

可以通过在Info.plist中将“Enable Multiple Windows”(“UIApplicationSupportsMultipleScenes”)设置为“NO”来使用新的UIScene生命周期功能而无需采用多窗口支持(这是新项目的默认设置)。这样,您可以逐步开始采用新的API。

您会发现场景委托方法名称与应用程序委托方法名称非常相似。一个令人困惑的问题是,应用程序委托方法没有被弃用,因此如果您同时拥有应用程序委托和场景委托方法,您不会收到警告,但只有一个方法会被调用。

UISceneDelegate接管的其他事项包括用户活动(continueUserActivity:等),状态恢复(stateRestorationActivityForScene:等),状态栏问题和打开URL。(我不确定这些是否替换了应用程序委托方法)。它还具有类似的生命周期事件通知(例如UISceneWillDeactivateNotification)。

来自WWDC Session,一些图片供您参考:

Swift的函数等效物:

enter image description here

类的职责:

enter image description here


2
谢谢,但它根本不起作用。有趣的是,当我不调试我的应用程序时,它完美地工作。 - Miguel
@Miguel 这很奇怪。在SO上开一个问题并提供更多细节。听起来像是有bug的行为。 - nevan king
3
没错,确实是这样。但说实话,我只是在创建一个新项目,并将所有源代码文件添加到其中。我已经花了太长时间来尝试解决它,甚至在苹果论坛上解释了情况,但没有人知道发生了什么。典型的XCode错误行为。 - Miguel
1
此外,“为多窗口设计您的应用程序”(https://developer.apple.com/videos/play/wwdc2019/258/) - AmitaiB
我可以确认,对于我的旧项目而言,它不使用多个窗口,AppDelegate的行为似乎已经发生了变化。特别是通过AppDelegate停止和启动音乐似乎不再正常工作。 - Mike Pandolfini
显示剩余5条评论

7

应用程序和场景生命周期不是同一回事!

enter image description here

在我看来,禁用应用程序状态改变方法的调用(以及在更改每个场景的状态时发送应用程序状态改变通知)是一个错误,即使有一个可以理解的意图强制程序员适应新的场景生命周期。
这里是一个场景代理模板,恢复了应用程序委托的预期应用程序状态改变方法的调用:
@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)
        }
    }
}

SceneDelegate.swift


7

这个帖子帮助了我:

在iOS 12中,视图控制器响应应用程序委托通知,但在iOS 13中不响应

Objective 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];
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接