ObjecTips

Swift & Objective-C で iOS とか macOS とか

iOS 8.0.2 iPad で Could not load NIB in bundle

クラッシュレポートにいくつか Could not load NIB in bundle のエラーが上がってきていたので調べてみた。
発生しているのはいずれも iOS 8.0.2 で機種は iPad Air, iPad mini 2 が確認された。
アプリ自体は iPhone のみ対応しているアプリで、iPhone ではクラッシュが発生していないので iPhone 専用アプリを iPad で使用している時にのみ起きている問題の様。

原因

クラッシュ時の Exception のメッセージは
Could not load NIB in bundle: 'NSBundle </private/var/mobile/Containers/Bundle/Application/<UUID>/<AppName>.app> (loaded)' with name '<XIBName>'
となっていて、どのNIB (XIB) ファイルが読み込みできなかったのかが分かる。

ビルド後の .app バンドルの中身を覗いてみると
Xcodeで扱っている該当の <XIBName>.xibコンパイル後に <XIBName>~iphone.nib という名称になっていた。

f:id:Koze:20150820213940p:plain

おそらくこの <XIBName>~iphone.nibiOS 8.0.2 の iPad からだと読み込み込めてない様子。

他のバージョンの OS では <XIBName>~ipad.nib が無ければ <XIBName>.nib を探しそれが無ければ <XIBName>~iphone.nib を探すという様な処理になっていると思われるが iOS 8.0.2 においては何らかの理由で <XIBName>~iphone.nib を探すという処理が行われていないと推測される。

発生条件

iOS 8.0.2 の iPad が手元に無いので実際にバグの発生させて確認する事ができないのだけど、レポートから考えると iPhone 専用アプリを iOS 8.0.2 の iPad で使用した時というのが条件としてあると思う。
(他の iOS ではクラッシュは確認できていないがもしかしたら他のバージョンでも起こるかも知れない。)

プロジェクトがユニバーサルアプリになっているとコンパイル後に <NIBName>~iphone.nib<NIBName>~ipad.nib が生成されていた。
iPad からは後者が読み込まれる事になるのでユニバーサルアプリではクラッシュは起きないはず。

f:id:Koze:20150820220712p:plain

ユニバーサルアプリの設定は Target > General > Deployment Info > Devices で変更可能。

ちなみにデバイス設定が iPad になっていると <NIBName>~ipad.nib のみが生成される。
iPad 専用アプリは iPhone にはインストールできないので iPad 専用アプリでは問題は起きない。

回避方法

Deployment Target が iOS 8 以降の場合はコンパイル後に
<NIBName>.nib
のみが生成される。
この場合には iPhone, iPad 共に正しくNIBファイルを読み込む事ができるはず。

f:id:Koze:20150820222807p:plain

Deployment Target が iOS 7 以降であってもXIBファイルの Size Classes をオフにしている場合にはコンパイル後に生成されるNIBファイルは <XIBName>.nib のみになる。
この場合もNIBファイルを正しく読み込む事ができるはず。

f:id:Koze:20150820223500p:plain f:id:Koze:20150820223553p:plain

まとめ
  • ユニバーサルアプリでは問題は起きない。
  • iPhone 専用アプリを iOS 8.0.2 iPad で使用した時のみに問題が起きる。
  • Deployment Target を iOS 8 以降にできるのであれば iOS 8 以降に設定する。
  • iOS 7 向けにビルドする必要がある場合はXIBファイルの Size Classes をオフにする。