70

我正在使用 Xcode 11 并为 iOS 13 构建应用程序。在我在 Xcode 中创建的一个新项目中,缺少一些 UIApplicationDelegate 方法,因此我将它们重新添加到应用程序委托文件中。“单一视图应用程序”项目的新模板缺少方法。问题是没有一个委托方法被调用 except -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
4

3 回答 3

186

iOS 13 提供了一种发送应用生命周期事件的新方式。而不是通过UIApplicationDelegate它们来通过UIWindowSceneDelegate这是一个UISceneDelegate子协议。UISceneDelegate有重要的委托方法。

此更改是为了在 iOS 13 中支持多个窗口。WWDC 2019 session 212 “ Introducing Multiple Windows on iPad ”中有更多信息。技术信息在14:30 左右开始,由一位穿着非常闪亮的高帮鞋的男士提供。较短的会话 258为多个 Windows 构建您的应用程序也很好地介绍了更改的内容。

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

  • applicationDidBecomeActive
  • applicationWillResignActive
  • applicationDidEnterBackground
  • applicationWillEnterForeground

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

如果你想恢复旧的行为,你需要

  1. 从应用的 Info.plist 中删除“Application Scene Manifest”条目
  2. 注释或删除application:configurationForConnectingSceneSession:options:方法(或 Swiftapplication(_:configurationForConnecting:options:)函数)
  3. 将 window 属性添加回您的应用委托 ( @property (strong, nonatomic) UIWindow *window;)

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

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

UIScene通过在 Info.plist 中将“启用多个窗口”(“UIApplicationSupportsMultipleScenes”)设置为“否”(这是新项目的默认设置),可以在不采用多窗口支持的情况下使用新的生命周期内容。通过这种方式,您可以以较小的步骤开始采用新的 API。

您可以看到场景委托方法名称与应用程序委托方法名称非常匹配。一件令人困惑的事情是,应用程序委托方法并未被弃用,因此如果您同时拥有应用程序委托和场景委托方法但只会调用一个,您将不会收到警告。

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

来自 WWDC 会议,为您提供了一些图片:

Swift 的等效函数:

在此处输入图像描述

班级职责:

在此处输入图像描述

于 2019-06-08T17:42:45.307 回答
6

这个线程帮助了我:

视图控制器在 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];
}
于 2019-11-06T08:55:00.593 回答
2

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

在此处输入图像描述

在我看来,禁用应用程序状态更改方法的调用(以及在更改每个场景的状态时发送应用程序状态更改通知)是一个错误,即使有一个可以理解的意图迫使程序员适应新的场景生命周期。

这是一个场景委托模板,用于恢复应用程序委托的应用程序状态更改方法的预期调用:

@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

于 2020-07-26T04:04:05.017 回答