今回は、Interface BuilderでMainMenu.nibとAbout.nibを編集し、その後にソースコードを記述してクラスを実装してみます。Leopard(Mac OS X 10.5)付属の「Xcode Tools」に付属している「Interface Builder 3」は、以前のバージョンから操作体系が大幅に変更されていますので、作業にはいくらか注意が必要となります。
「しんぶんし v3.0」で使うモデル、ビュー、コントローラの各オブジェクトは、すべてをMainMenu.nibに詰め込むことはしません。オブジェクトは関連するグループに分けて、別々のnibファイルにまとめる予定です。まず最初に、MainMenu.nibにはアプリケーション自身のコントローラ・オブジェクトである「ApplicationController」を登録します。そして続いて「About.nib」ファイルを作成し、そちらにアバウトウィンドウや、そのコントローラである「AboutController」を登録します。
XcodeのShinbunShi3プロジェクトを起動し、登録されているMainMenu.nibをダブルクリックしてInterface Builderを立ち上げます。表示された「ライブラリ」ウィンドウ(何故かここだけ日本語表記?)にある「NSObject」(青い立方体 アイコン)をドラッグ&ドロップでMainMenu.nibへ登録します。 その名称をObjectからApplicationControllerに変更したら、インスペクタ(Inspector)ウィンドウをオープンし、IdentityパネルのClassカラムににもApplicationConrollerと代入します。この作業により、アプリケーション起動時に、自動的にApplicationConrollerオブジェクトのインスタンスが生成されることになります。
ここまでの作業を行うことで、Interface BuilderがXcodeプロジェクトのクラス定義(ApplicationController.hファイルの内容)との同期を取り、自動的にIBActionである「openAboutWindow:」がClass Actionsのリストに追加されます(これは便利!)。この時、もし対象クラスにIBOutletが存在していれば、それについても、すぐ下のClass Outletsのリストに登録されます。ところで、旧バージョンのInterface Builderであれば、XcodeプロジェクトのApplicationConroller.hをMainMenu.nibウィンドウ上へドラッッグ&ドロップすれば、そのクラスのインスタンス・オブジェクトを作成してくれたのですが、何故だか本バージョンでは何も起こりません?
この機能は削除されてしまったのかと思い「Interface Builder User Guide」を調べてみると、そこにはちゃんと可能であると明記されています。その証拠に、Fileメニューにも「Read Class Files...」がありますので、機能自体が無くなったわけではなさそうです。ならばと、メニューを選択してApplicationConroller.hファイルを読み込んでみましたが、やはり何も起こりません?同時に、Fileメニューの「Write Class Files...」も試してみましたが、こちらの方は、ちゃんとApplicationConroller.hとApplicationConroller.mの両ファイルを書き出してくれます。これはバグでしょうか?それとも当方の環境だけで起こる現象でしょうか?謎のままです。
そもそもInterface Builder 3には「Classes」メニューがありません。つまり、旧バージョンで行っていたように、Classesタブを使い先んじて指定クラス(例えばNSObjectなど)のサブクラスを作成しておき、そこから「Classes」メニューの「Instantiate」によりインスタンス・オブジェクトを作成するという作業ができません。またインスペクタにはスーパークラスを指定する箇所がないので、Interface Builder側で作成したインスタンスをファイルへ書き出すと、スーパークラスの表記ができず、ヘッダファイルには以下の様な注意書きが付きます(笑)。
@interface MyObject : /* Specify a superclass (eg: NSObject or NSView) */ {
}
@end
つまり、Interface Builder側でクラスを作成し、それからソースファイル(クラス定義と実装の雛形)を書き出すという従来の流れは推奨されていないようです。これからは、先んじてクラス定義のヘッダファイルを作成し、nibファイに対応インスタンス・オブジェクトを登録してから、それと同期させるという作業の流れになりそうです。ソースコードに新規のClass ActionやOutletを追加した時も、Interface Builderがすぐさま同期させてnibファイル側にも反映させてくれますので、この流れの方が分かり易いと思います。ただし、昔からの Interface Builderの使い手は、最初は少々戸惑うかもしれませんね。
次にAbout.nibファイルの方です。こちらでは、アバウト表示用のウィンドウ(ビュー・オブジェクト)とアバウト用のコントローラ・オブジェクトを編集します。nibファイルを新規作成するには、Fileメニューから「New...」を選びます。表示されたダイアログの「Window」を選択し、できあがったnibファイルを「About.nib」という名称で保存した後にXcodeプロジェクトに登録しておきます。この時、nibファイル内のウィンドウ名称もAboutと変更しておきます。ウィンドウ上には「OK」ボタンや画像を配置することになりますが、その作業の解説は次回にまわします。また、Interface Builderでのコントローラとビューのリンクについても次回に解説したいと思います。
アバウトウィンドウ用のAboutControllerについては、ApplicationConrollerのようにライブラリからNSObjectアイコンを登録する必要はありません。About.nibの「File's Owner」アイコンを選択してインスペクタをオープンし、IdentityパネルのClassカラムにAboutControllerと代入します。 後は、AboutControllerオブジェクトのインスタンスを作成する時に、このnibファイルを読みむように処理すればOKです。また、プロジェクトのクラス定義(AboutController.hファイル)とも同期が取られ、IBActionの「closeAbout:」がClass Actionsリストに、IBOutletの「_okButton」がClass Outletsリストの方に表示されます。
続いてクラスの実装ですが、とりあえず以下の様にソースコードで記述してみました。前回、各クラスのインスタンス変数は、ローカル変数と区別しやすくするためにアンダーバーを含むように表記しましたが、アンダーバーは先頭にあった方が良さそうなので(後々のことを考えると)そう変更してあります。
まずは、ApplicationConroller.mです。
#import "ApplicationConroller.h"
@implementation ApplicationConroller
- (IBAction)openAboutWindow:(id)sender
{
if( ! _aboutController )
_aboutController=[[AboutController alloc] init];
[[_aboutController window] center];
[_aboutController showWindow:self];
}
- (void)dealloc
{
[_aboutController release];
[super dealloc];
}
@end
続いて、AboutController.mの方です。
#import "AboutController.h"
@implementation AboutController
- (id)init
{
self=[super initWithWindowNibName:@"About"];
return self;
}
- (IBAction)closeAbout:(id)sender
{
[self close];
}
@end
次回は、ウィンドウへのボタンや画像の配置、コントロールとビューのリンク、上記ソースコードの詳しい解説を行います。また、練習用に追加した不要なコード部分を外す処理もします。本連載で作成したプロジェクトファイルは、MOSA Exchangeに順次アップロードされています。今回分の名称は「ShinbunShi3_08_01_11.zip」です。