Xcode11 創建的項目運行閃退或黑屏怎么解決?

1. 問題及原因

1.1 問題

????????首先聲明一下這里說的問題是針對通過代碼的方式來進入程序而不是通過Storyboard。通過Xcode11之前的版本創建項目后,將AppDelegate.m文件中的application: didFinishLaunchingWithOptions:方法的實現改為下面的代碼就可以通過代碼設置rootViewController來啟動程序了。

- (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;
}

????????但是當我們用Xcode11創建項目通過同樣的方式來啟動時,發現程序閃退了,原因如下圖所示:


運行報錯
1.2 造成這個問題的原因

????????我們發現,通過Xcode11創建的工程除了有AppDelegate這個類文件,還多出來一個SceneDelegate類文件。多出來的這個類時用來干嘛的呢?這是iPadOS帶來的用來支持多窗口的。
????????在iOS13之前,Appdelegate的職責全權處理App生命周期和UI生命周期。
????????而在iOS 13之后就發生了變化,UI生命周期變成由SceneDelegate來負責,而Appdelegate負責APP的生命周期和SceneDelegate的生命周期。所以還是像之前那么處理的話就會出問題。

2. 解決方案一

????????如果我們項目中不需要支持多窗口,那我們就不需要用到SceneDelegate
????????第一步,先將項目的Info.plist文件中的Application Scene Manifest這一項刪掉,然后刪掉SceneDelegate .hSceneDelegate.m文件(這兩個文件不刪也不會有影響)。

????????第二步,在AppDelegate .h文件中添加@property (nonatomic , strong) UIWindow *window;,然后將AppDelegate.m文件中的application: didFinishLaunchingWithOptions:方法的實現改為下面的代碼。

- (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;
}

????????第三步,經過前面2步操作后運行程序不會閃退了,但是發現黑屏,還需要將AppDelegate.m中的下面2個方法刪掉。這樣就可以正常啟動程序了。

#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. 解決方案二

????????如果我項目中有多窗口開發相關的需求,或者需要保留SceneDelegate相關的內容該怎么辦呢?首先我們這里不采用Storyboard的方式來啟動,先刪掉項目中Main.storyboard文件,然后打開項目的Info.plist文件,刪掉下圖用紅色框起來的兩項。

刪掉這兩項

????????然后在SceneDelegate.m文件的scene: willConnectToSession: options:方法中設置windowrootViewController,代碼如下所示:

- (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的設備中正常運行了,但是再iOS 13以下的設備上運行會黑屏,所以還需要適配iOS 13以下的系統。首先在AppDelegate .h文件中添加@property (nonatomic , strong) UIWindow *window;,然后將AppDelegate.m文件中的application: didFinishLaunchingWithOptions:方法的實現改為下面的代碼。這樣就可以在所有系統上都能正常運行了。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
    
    // @available(iOS 13.0,*)表示iOS 13.0及以上的系統,后面的*表示所有平臺
    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;
}
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容