You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

iOS 13下Xcode11开发中App Delegate方法除启动外均未触发

iOS 13 下 AppDelegate 代理方法未调用的解决方案

兄弟,我太懂你踩的这个坑了!iOS 13 引入了UIScene这个新架构之后,AppDelegate的职责被拆分了——原来它既要管应用级的生命周期,又要管界面场景的生命周期,但现在大部分界面相关的回调都移到SceneDelegate里了,这就是你手动加的那些代理方法没被触发的原因。

一、适配 UIScene 架构的正确做法

新建的 iOS 13 项目默认会生成SceneDelegate.hSceneDelegate.m文件,你需要把原来放在AppDelegate里的场景级生命周期方法移到这个文件中,对应关系如下:

  • applicationDidEnterBackground:sceneDidEnterBackground:
  • applicationWillEnterForeground:sceneWillEnterForeground:
  • applicationWillResignActive:sceneWillResignActive:
  • applicationDidBecomeActive:sceneDidBecomeActive:

修正后的SceneDelegate.m代码示例:

@implementation SceneDelegate

- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
    // 这里做界面初始化,类似原来didFinishLaunching里的逻辑
    UIWindowScene *windowScene = (UIWindowScene *)scene;
    self.window = [[UIWindow alloc] initWithWindowScene:windowScene];
    self.window.rootViewController = [[UIViewController alloc] init]; // 替换成你的根控制器
    [self.window makeKeyAndVisible];
}

- (void)sceneDidEnterBackground:(UIScene *)scene {
    NSLog(@"sceneDidEnterBackground:");
    // 原来applicationDidEnterBackground的逻辑放在这里
}

- (void)sceneWillEnterForeground:(UIScene *)scene {
    NSLog(@"sceneWillEnterForeground:");
    // 原来applicationWillEnterForeground的逻辑放在这里
}

- (void)sceneDidBecomeActive:(UIScene *)scene {
    // 对应原来的applicationDidBecomeActive
}

- (void)sceneWillResignActive:(UIScene *)scene {
    // 对应原来的applicationWillResignActive
}

@end

你的AppDelegate只需要保留应用级的方法即可,不用再添加场景生命周期相关方法:

@implementation AppDelegate

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSLog(@"application:didFinishLaunchingWithOptions:");
    return YES;
}

#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

二、关闭 UIScene,回到旧版 AppDelegate 模式

如果你的项目不需要多场景支持(比如只适配iPhone,不需要iPad多窗口),也可以直接关闭UIScene,回到原来的AppDelegate全权负责的模式:

  1. 打开项目的Info.plist,找到Application Scene Manifest条目,右键删除整个节点
  2. 删除项目中的SceneDelegate.hSceneDelegate.m文件
  3. 修改AppDelegate.h,添加UIWindow属性:
#import <UIKit/UIKit.h>

@interface AppDelegate : UIResponder <UIApplicationDelegate>

@property (strong, nonatomic) UIWindow *window;

@end
  1. 修改AppDelegate.m,在didFinishLaunchingWithOptions里初始化window:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    NSLog(@"application:didFinishLaunchingWithOptions:");
    
    // 初始化window和根控制器
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.rootViewController = [[UIViewController alloc] init]; // 替换成你的根控制器
    [self.window makeKeyAndVisible];
    
    return YES;
}
  1. 现在你原来手动添加的applicationDidEnterBackground等方法就可以正常被调用了!

内容的提问来源于stack exchange,提问作者nevan king

火山引擎 最新活动