hatenablogから2018-12-10の記事を移行しました。
https://bitsandbobs.hatenablog.jp/entry/2018/12/10/025556
ViewController と xib ファイルを作って Storyboard から呼び出す手順をまとめておく。
!注意!これは Cocoa App (macOS アプリ) に関する記事です。
環境
- macOS High Sierra 10.13.6
- Xcode 10.1
手順
ViewController と xib ファイルを作成する
macOS / Cocoa Class を選択して Next
Subclass of は NSViewController を選択
Also create XIB file for .. のチェックオン (手間が省けるので)
クラス名を入力して Next → Create
ViewController のソースファイルと、同名の xib ファイルが作成される
xib の編集
File's owner の Custom Class 名に先ほど作ったクラスが設定されていることを確認しておく
その後、好きなように View にアレコレ追加していく(割愛)
Storyboard の編集
View Controller の Custom Class 名に作ったクラスを指定する
デフォルトで作られている View を Storyboard から削除しておく
(Storyboard に View が残っていると xib ファイルではなく、この View を優先して表示するため)
あとがき
当初 xib ファイルが読み込まれずどハマりしました。
Storyboard で ViewController を追加したときに初期作成される View を削除してなかったからですが、単純なことほど気づきにくいものですね。
この問題の原因を調べる過程でわかったことを以下にまとめておきます。
- ViewController が View を初期化するとき(loadView がコールされるとき) nibName プロパティが nil の場合はクラス名と同名の xib ファイルをロードする
Prior to OS X v10.10, the loadView() method did not provide well-defined behavior if the nibName property’s value was nil. In macOS 10.10 and later, however, you get correct behavior without specifying a nib name as long as the nib file’s name is the same as that of the view controller.
loadView() - NSViewController | Apple Developer Documentation
- ViewController が Storyboard からインスタンス化されるときは init(nibName: bundle:) ではなく init(coder:) コンストラクタがコールされる
- Storyboard にて ViewController に View が設定されている場合は、nibName = ViewController の Object ID1 + "-view-" + View の Object ID (例: "XfG-lQ-9wD-view-Qcj-BY-oc5")となる
- Storyboard にて ViewController に View が設定されていない場合は nibName = nil となる
ちなみに調査の過程で以下の方法を試しました。
困ったことに、これらは全て期待する動きをしたのですよね。
- NSViewController の修正
- viewDidLoad で NSNib#instantiate
- loadView をオーバーライドして NSNib#instantiate
- init(coder:) をオーバーライドして super.init(nibName: bundle:)
- nibName プロパティをオーバーライドして nil またはクラス名を返す
- Storyboard の修正
- User Defined Runtime Attributes に nibName:String を追加する
- Storyboard の ViewController から View を消す(!!!)
Runtime Attributes に nibName を追加する方法は ViewController クラスは作らないけど View は xib で外だしにしたいときとかに使えそうです。
nibName や init(coder:) をオーバーライドする方法は xib のファイル名がクラス名と異なるとき(例えば、動的にViewを切り替えるときなど)に使えるかもしれません。
参考
-
Object ID は Identity inspector の Document に表示されている ↩