1. 問題及原因
1.1 問題
????????首先聲明一下這里說的問題是針對(duì)通過代碼的方式來進(jìn)入程序而不是通過Storyboard。通過Xcode11之前的版本創(chuàng)建項(xiàng)目后,將AppDelegate.m文件中的application: didFinishLaunchingWithOptions:方法的實(shí)現(xiàn)改為下面的代碼就可以通過代碼設(shè)置rootViewController來啟動(dòng)程序了。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
self.window.backgroundColor = UIColor.whiteColor;
[self.window makeKeyAndVisible];
self.window.rootViewController = [ViewController new];
return YES;
}
????????但是當(dāng)我們用Xcode11創(chuàng)建項(xiàng)目通過同樣的方式來啟動(dòng)時(shí),發(fā)現(xiàn)程序閃退了,原因如下圖所示:

1.2 造成這個(gè)問題的原因
????????我們發(fā)現(xiàn),通過Xcode11創(chuàng)建的工程除了有AppDelegate這個(gè)類文件,還多出來一個(gè)SceneDelegate類文件。多出來的這個(gè)類時(shí)用來干嘛的呢?這是iPadOS帶來的用來支持多窗口的。
????????在iOS13之前,Appdelegate的職責(zé)全權(quán)處理App生命周期和UI生命周期。
????????而在iOS 13之后就發(fā)生了變化,UI生命周期變成由SceneDelegate來負(fù)責(zé),而Appdelegate負(fù)責(zé)APP的生命周期和SceneDelegate的生命周期。所以還是像之前那么處理的話就會(huì)出問題。
2. 解決方案一
????????如果我們項(xiàng)目中不需要支持多窗口,那我們就不需要用到SceneDelegate。
????????第一步,先將項(xiàng)目的Info.plist文件中的Application Scene Manifest這一項(xiàng)刪掉,然后刪掉SceneDelegate .h和SceneDelegate.m文件(這兩個(gè)文件不刪也不會(huì)有影響)。
????????第二步,在AppDelegate .h文件中添加@property (nonatomic , strong) UIWindow *window;,然后將AppDelegate.m文件中的application: didFinishLaunchingWithOptions:方法的實(shí)現(xiàn)改為下面的代碼。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions{
self.window = [[UIWindow alloc] initWithFrame:UIScreen.mainScreen.bounds];
self.window.backgroundColor = UIColor.whiteColor;
[self.window makeKeyAndVisible];
self.window.rootViewController = [ViewController new];
return YES;
}
????????第三步,經(jīng)過前面2步操作后運(yùn)行程序不會(huì)閃退了,但是發(fā)現(xiàn)黑屏,還需要將AppDelegate.m中的下面2個(gè)方法刪掉。這樣就可以正常啟動(dòng)程序了。
#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 {
}
3. 解決方案二
????????如果我項(xiàng)目中有多窗口開發(fā)相關(guān)的需求,或者需要保留SceneDelegate相關(guān)的內(nèi)容該怎么辦呢?首先我們這里不采用Storyboard的方式來啟動(dòng),先刪掉項(xiàng)目中Main.storyboard文件,然后打開項(xiàng)目的Info.plist文件,刪掉下圖用紅色框起來的兩項(xiàng)。

????????然后在
SceneDelegate.m文件的scene: willConnectToSession: options:方法中設(shè)置window和rootViewController,代碼如下所示:
- (void)scene:(UIScene *)scene willConnectToSession:(UISceneSession *)session options:(UISceneConnectionOptions *)connectionOptions {
self.window = [[UIWindow alloc] initWithWindowScene:(UIWindowScene *)scene];
self.window.backgroundColor = UIColor.whiteColor;
[self.window makeKeyAndVisible];
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:[ViewController new]];
}
????????這樣程序就可以在iOS 13的設(shè)備中正常運(yùn)行了,但是再iOS 13以下的設(shè)備上運(yùn)行會(huì)黑屏,所以還需要適配iOS 13以下的系統(tǒng)。首先在AppDelegate .h文件中添加@property (nonatomic , strong) UIWindow *window;,然后將AppDelegate.m文件中的application: didFinishLaunchingWithOptions:方法的實(shí)現(xiàn)改為下面的代碼。這樣就可以在所有系統(tǒng)上都能正常運(yùn)行了。
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// @available(iOS 13.0,*)表示iOS 13.0及以上的系統(tǒng),后面的*表示所有平臺(tái)
if (@available(iOS 13.0,*)) {
}else{
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
self.window.backgroundColor = UIColor.whiteColor;
[self.window makeKeyAndVisible];
ViewController *vc = [ViewController new];
self.window.rootViewController = [[UINavigationController alloc] initWithRootViewController:vc];
}
return YES;
}