iOS 13下Xcode11开发中App Delegate方法除启动外均未触发
iOS 13 下 AppDelegate 代理方法未调用的解决方案
兄弟,我太懂你踩的这个坑了!iOS 13 引入了UIScene这个新架构之后,AppDelegate的职责被拆分了——原来它既要管应用级的生命周期,又要管界面场景的生命周期,但现在大部分界面相关的回调都移到SceneDelegate里了,这就是你手动加的那些代理方法没被触发的原因。
一、适配 UIScene 架构的正确做法
新建的 iOS 13 项目默认会生成SceneDelegate.h和SceneDelegate.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全权负责的模式:
- 打开项目的
Info.plist,找到Application Scene Manifest条目,右键删除整个节点 - 删除项目中的
SceneDelegate.h和SceneDelegate.m文件 - 修改
AppDelegate.h,添加UIWindow属性:
#import <UIKit/UIKit.h> @interface AppDelegate : UIResponder <UIApplicationDelegate> @property (strong, nonatomic) UIWindow *window; @end
- 修改
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; }
- 现在你原来手动添加的
applicationDidEnterBackground等方法就可以正常被调用了!
内容的提问来源于stack exchange,提问作者nevan king




