🍎

Interface Builderを使わずにMacアプリケーション作成 - nib検証篇 1

2020/09/20に公開

アプリケーション起動時に実行されるmain()関数

main.m
int main(int argc, char *argv[])
{
    return NSApplicationMain(argc, (const char **)argv);
}

アプリケーションの起動とは、つまりmain.m内に定義されているmain()関数を実行すること。戻り値型はintで、これはNSApplicationMain()関数で発生したループ(後述)が終了したときに返される値のようだ。

この中で指定されているNSApplicationMain()関数は、AppKit.framework内のNSApplicationクラスで定義されている。NSApplicationクラスの継承関係はNSObject > NSResponder > NSApplicationの順。

NSApplicationMain()関数の処理内容

NSApplicationMain()関数の実装は公開されていないが、NSApplicationクラスリファレンスにて概要は公開されていたので引用する。

NSApplicationMain()
void NSApplicationMain(int argc, char *argv[])
{
    [NSApplication sharedApplication];
    [NSBundle loadNibNamed:@"myMain" owner:NSApp];
    [NSApp run];
}

これはNSApplicationMain()の動作を例として表した類似コードであり、上記の通りに実装されているわけではない。この処理の概要は次のようになる。

  • + (NSApplication *)sharedApplicationクラスメソッドがアプリケーションオブジェクトを作成しNSAppグローバル変数に代入
    • これはシングルトンなインスタンス
  • 指定のxib(からコンパイルされたnib)をロードする
  • NSAppに対して- (void)runメソッドを送信
    • このメソッドはNSApplicationで定義
    • - runによってメインイベントループが開始する
    • このループは- stop:- terminate:を送信するまで継続する

loadNibNamed:owner:について

注意すべきなのはOS X 10.8では+ loadNibNamed:owner:メソッドはDeprecatedである点。なので、10.8より定義された- loadNibNamed:owner:topLevelObjects:を使っていると思われる。これはインスタンスメソッドなので、推測される実装はおそらく以下のようなもの。(13/4/21追記:ここで間違った情報を記載してしまいました。nib検証篇 4で扱っています。)

起動時に読み込むxibはどこで指定しているか

これは(Project Name)-info.plist内のMain nib file base name Keyで指定されている。この指定を変更するとどうなるか。

Main nib file base nameに該当しないファイル名fooを指定した場合

console
2013-04-20 14:01:10.489 withoutIB[1386:303] Unable to load nib file: foo, exiting
  • アプリケーション withoutIB は__起動しない__。

Main nib file base nameを空欄にした場合

console
2013-04-20 14:01:38.213 withoutIB[1399:303] Could not connect the action buttonPressed: to target of class NSApplication
2013-04-20 14:01:38.214 withoutIB[1399:303] Could not connect the action buttonPressed: to target of class NSApplication
2013-04-20 14:01:38.215 withoutIB[1399:303] Could not connect the action buttonPressed: to target of class NSApplication
2013-04-20 14:01:38.215 withoutIB[1399:303] Could not connect the action buttonPressed: to target of class NSApplication
  • この時点でアプリケーション withoutIB は__起動している__。
    • ただしメニューバーにはアップルメニューとアプリケーションメニューの二つのみ表示。
    • アプリケーションメニューの中身は空でcmd+Qといった標準操作も受け付けない。
  • 興味深いのは、4回エラーを出している点。

仮説

nibを読み込むときの処理を全てコードで記述すれば、Interface Builderを用いずにアプリケーションを起動させることができるか?*1

次回に続きます。


注釈

*1: 掲載当時nibの必要性についての検証が不十分な状態での仮説です。現在は、nibは必要と結論が出ていますのでご了承ください。(13/4/24追記)

リンク

Discussion