Cocoa Frameworkを用いると、ソースコードをあまり記述しなくても色々処理がこなせるようになります。その理由のひとつがNibファイルの仕組みにあります。今回から、新規プロジェクトで作られる2つのNibファイル、MainMenu.nibとMyDocument.nibの内容を詳しく調べてみたいと思います。
具体的に中身を調べる前に、まずCarbonからCocoaへ移行する場合の問題点を復習しておきましょう。最初からアプリケーション開発をObjective-CとCocoaで行う場合は問題無いのですが、C/C++とCarbonや別Frameworkで開発作業をしてきた人にとって「既存アプリケーションをCocoaで作り直す」作業には、多数のハードルが存在します。そのうち、まず最初にぶつかるのは以下の2点です。
・リソースファイル依存からの脱却
・nibファイル自身のコンバート作業
昔々、旧Mac OS 9用アプリケーション(CFM形式)をMac OS X用のCarbonアプリケーション(Mach-O形式)へと作り直す時に、リソースファイルに保存されていたダイアログやコントロールの雛形(Framework依存の雛形データ)をCarbon用Nibファイルへと変更する作業が発生しました。こうした作業には、アプリケーションが大規模になればなるほ膨大な時間が必要となります。現実に、この作業がネックとなり、随分長い間Mach-O形式にできず、結局Universal Binary化も遅れに遅れた大手メーカのアプリケーションもあります。つまり、ソースコードの移行とは別に、もうひとつの大仕事が存在したわけです。
同様な事が、プログラミングモデルをCarbonからCocoaへ移行する時にも発生します。つまり、CarbonとCocoaのNibファイルはまったくフォーマットが異なるため、その変換を手作業で行う必要があるのです。またCarbonでは、文字列、カーソル、アイコン、画像などはリソースに保存されていることが多く、それらをCocoaで使える形式に変える作業も生じます。CFMからMach-Oへの移行では、各種リソースをNibファイルへと変換する機能(限定的)がInterface Builderに用意されていたため、変換作業をそこそこ自動化することができました。しかし、今回はそうした仕組みもありません。
試しに、Carbon用Nibファイルからウィンドウオブジェクトをコピーし、Cocoa用Nibファイルへペーストしても何も起こりません。まあ、ウィンドウを2,3しか使わない小規模なアプリケーションであれば、Nibファイルの変換も大した労力ではありません。しかし、ウィンドウ定義だけでも数百あり、その上に配置されたコントロールは千を越えるようなケースを想像してみてください。現実に筆者も幾つかそうしたプロジェクトを抱えていますが、NibファイルをCocoa用に作り直す作業に対し、利益に見合った時間と人件費を捻出することは容易ではありません。ましてや、これを1人や2人で行わなければいけないとすると「Carbonのままでイイや!」という結論が浮かぶのも至極当然なわけです。
では「もっと賢く」という事で、CarbonとCocoaのNibファイルをXMLファイルに書き出して、それを解析(フォーマット未公開)することで自動変換ツールを作ろうかとも考えましたが、両フォーマットがあまりにも違うため、あっさりあきらめてしまいました。まあ、変換が容易であればApple社自身が提供しているはずですから、これは仕方のない結果でしょう。Apple社がCocoa普及を促進したいのであれば、これぐらいのツールを提供してもバチは当たらないと思うのですが...。ついでに、引き続き行うアクションやアウトレットをターゲットに接続する作業も考慮すると「Cocoaにするのは止めておこうか」という思考に拍車がかかります(笑)。
Interface BuilderやNibファイル関連の問題については、実際に開発を行う過程でも言及していきます。それではさっそくプロジェクトに含まれるMainMenu.nibとMyDocument.nibの中身を見てみます。まず最初にMainMenu.nibをInterface Builderで開くと、Carbon用NibファイルのMenuBarやMainWindowに準ずるMainMenuとWindowの2つのアイコン(オブジェクト)が表示されます。それに加えて、File's OwnerとFirst ResponderというCarbonにはないアイコンも見受けられます。次にMyDocument.nibの方を開くと、MainMenuがなくFile's Ownerのアイコンの形状がMainMenu.nibのそれとは違うことが分かります。
Carbon用のNibファイルは、Interface Builderで編集したメニュー、コントロール、ウィンドなどの表示用オブジェクトをSetMenuBarFromNib()やCreateWindowFromNib()を使い実体化するために用意します。以前はこの役割をリソースとCreateWindowFromResource()が受け持っていました。こうした方法を取らないとすると、ウィンドウはソースコード上にCreateNewWindow()などのAPIを記述して作成することになります。CreateNewWindow()には、ウィンドウの表示枠サイズや表示位置、種類、各種の 属性(アトリビュート)などを設定する必要があり、ウィンドウタイトルを変えるにはSetWindowTitleWithCFString()などの別APIを呼ぶ必要もあります。
こうした表示用オブジェクトをソースコードで記述するのは、イメージ化が難しく面倒な作業です。加えて、使うオブジェクトの量と共に記述すべきソースコードの量も増大していきます。Nibファイルを使えば、Interface Builderで編集した状態がそのまま表示されるわけですから、イメージ化困難等の問題は解消されます。ウィンドウやコントロールに使う文字列も、日本語と英語のものをNibファイルに用意し、それぞれJapanese.lprojとEnglish.lprojフォルダに入れておけば、多国語にローカライズされたアプリケーションを簡単に提供することが可能となります。
しかし、現在の開発作業では、こうした表示用オブジェクトの編集に時間を費やすことも負担となっています。筆者がMac OS X用アプリケーションをCFM形式からMach-O形式へ速攻で切り替えた理由のひとつは、Interface Builderでの編集機能が、リソース編集ツール(ResEditやResorcerer)より強力で使いやすかったからです。これは直ちに開発時間の短縮につながります。CarbonからCocoaへの移行では、表示用オブジェクトの編集自体に大きな違いはありません。しかし、編集可能なコントロールとそのオプションの種類はCocoaの方が多く、アプリケーションの機能を充実させるためのメリットは増えます。
最近のOOP(オブジェクト指向プログラミング)開発環境では、アプリケーションを形成するオブジェクトの役割分担を指して、モデル・ビュー・コントローラー(MVCモデル)と呼びます。詳しいことは本連載中に逐次解説する予定ですが、Carbon用のNibファイルはこのうちビュー(表示用)オブジェクトの雛形だけを保持できます。それがMenuBarやMainWindowであり、Cocoaの方ではMainMenuやWindowとなります。しかし、Cocoa用のNibファイルは、ビューに加えてコントローラーやモデルオブジェクトも部分的に保持可能となっています。こちらが、File's OwnerとFirst Responderに関する仕組みとなります。ちなみに、この仕組みはCarbon用のNibファイルには存在しません。
次回も引き続き、Cocoaプロジェクトに含まれるMainMenu.nibとMyDocument.nibの中身を調査します。File's OwnerとFirst Responderアイコンは具体的にどんな機能を受け持っているのでしょうか? さらに詳しく調べてみましょう。