Posted at

iOS9でアプリが起動直後にクラッシュする場合の回避方法

More than 3 years have passed since last update.


はじめに

とあるアプリをiOS9 beta3にて動作確認をしていたところ、起動直後にフリーズしてしまい、数秒後にクラッシュする現象が起こっていました。

動作確認環境


  • iOS9 beta3

  • Xcode7.0 beta3

エラーログを確認したところ下記のエラーがでていました。

Application windows are expected to have a root view controller at the end of application launch

*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Application windows are expected to have a root view controller at the end of application launch'

*** First throw call stack:
(
0 CoreFoundation 0x000000010b9cf7c5 __exceptionPreprocess + 165
1 libobjc.A.dylib 0x000000010afdadcd objc_exception_throw + 48
2 CoreFoundation 0x000000010b9cf62a +[NSException raise:format:arguments:] + 106
3 Foundation 0x000000010ac14bf1 -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 198
4 UIKit 0x00000001097c3eca -[UIApplication _runWithMainScene:transitionContext:completion:] + 2875
5 UIKit 0x00000001097c1208 -[UIApplication workspaceDidEndTransaction:] + 188
6 FrontBoardServices 0x000000010fee1c0f -[FBSSerialQueue _performNext] + 192
7 FrontBoardServices 0x000000010fee1f7d -[FBSSerialQueue _performNextFromRunLoopSource] + 45
8 CoreFoundation 0x000000010b8f9ba1 __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ + 17
9 CoreFoundation 0x000000010b8efacc __CFRunLoopDoSources0 + 556
10 CoreFoundation 0x000000010b8eef83 __CFRunLoopRun + 867
11 CoreFoundation 0x000000010b8ee998 CFRunLoopRunSpecific + 488
12 UIKit 0x00000001097c0ba5 -[UIApplication _run] + 402
13 UIKit 0x00000001097c52cb UIApplicationMain + 171
14 TestApp 0x0000000108968d8f main + 111
15 libdyld.dylib 0x000000010d4e292d start + 1
16 ??? 0x0000000000000001 0x0 + 1
)

アプリ起動時にwindowにrootViewがセットされていないとの事ですが、

iOS8以前は動作していた事を考えるとiOS9からここら辺の挙動が変更されているみたいです。

(beta版のため、製品版では発生しない可能性はあります)

実装を見てみると下記のようになっていました。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{
// ウィンドウ初期化
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
[self.window makeKeyAndVisible];

return YES;
}

windowのrootViewControllerがセットされていませんね。

どうやらこのアプリはアプリ起動時に初回起動かどうかを判定してrootViewControllerを出し分けている処理が別にありましたが、

blocksを挟んだ非同期での処理だったため、アプリ起動時にrootViewControllerが存在しない状態になっていました。


対応方法

対応方法でもなんでもないですが、windowのrootViewControllerを正しくセットすれば動作しました。

(とりあえずで空のViewControllerをセット)

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{
// ウィンドウ初期化
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = [UIViewController new];
[self.window makeKeyAndVisible];

return YES;
}

あとは下記のような実装でもクラッシュする原因となってしまいますので、rootViewControllerに正しくセットするようにしましょう。

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions

{
// ウィンドウ初期化
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
UIViewController *viewController = [UIViewController new];
[window addSubview:viewController.view];
[self.window makeKeyAndVisible];

return YES;
}


終わりに

アプリは正しく実装しましょうというAppleさんの意思を垣間見た気がしました。

(いや、言われなくても正しい実装を心がけましょうw)

詳しくは調べていないですが、Xcode6.xでビルドしたアプリをiOS9で実行した場合でもクラッシュしたので、beta版の不具合の可能性もありますが、今後のアップデートで確認していこうと思います。