今回は、「しんぶんし 3」プロジェクトを「Cocoa Document-based Application」に切り替えてみます。こちらのアプリケーションタイプで注意すべき点を調査しながら、モデル・オブジェクトの実装を考えたいと思います。
さて、プロジェクトの引っ越しをしましょう。Xcodeで新規プロジェクトを作成する時に「 Cocoa Document-based Application」テンプレート(雛形)を選択します。プロジェクトの名称は「Shinbunshi3」を引き継ぎます。新規プロジェクトが保存されたら、前回のプロジェクトの「Resources」フォルダ内の画像、アイコン、InfoPlist.stringsファイルを移動させます。nibファイルについては、About.nibの方は、そのまま移動してもかまいませんが、MainMenu.nibは作り直す必要があります。
メニューオブジェクト(MainMenu)のタイトルやアイテムを日本語にローカライズしたら、ApplicationConrollerを再度作成して、アバウトメニューにopenAboutWindow:(アクション・メソッド)を割り当てます。この作業を行っていて気づいたのですが、編集メニューの「検索」と「自動置換」アイテムのサブメニューに、まったく同じコマンドキーが割り振られています。Xcodeのテンプレート作成時のバグだと思いますので(多分)、「自動置換」の方のコマンドキー割り当ては消しておきましょう。
前プロジェクトとは異なり、MainMenu.nibの方にはメインウィンドウのオブジェクトは登録されていません。プロジェクトのウィンドウ(今回はドキュメントウィンドウと呼ぶ)は、新規作成されたMyDocument.nibの方に登録されています。また、Info.plistファイルも、ターゲットの情報ダイアログの「プロパティ」で編集し直し、前回と同等に仕上げておきます。ただし、この時に注意しなければいけないのは、「書類のタイプ」の一番上に登録されている「名称」がDocumentTypeで「クラス」がmyDocumentの内容を消さないことです。
一番上の設定が「しんぶんし 3」のドキュメントタイプとなりますので、「拡張子」にsinbを「OSタイプ」に'SinB'を追加しておきます。 その下に、前回の画像ファイルのタイプなどを追加すればOKです。 それから、せっかくですので、ドキュメントファイル用のアイコンも「SinB.icns」という名称で登録しておきます。アイコンファイルの方は、アプリアイコンと同じ場所に保存しておき、アプリケーション・バンドルへとコピーされるように新プロジェクトのResourcesグループにも登録してきます。
最後はソースファイルです。アバウトダイアログ用に作成した、ApplicationConroller.mとApplicationConroller.hは、そのまま新プロジェクトに登録しても大丈夫です。それから、新プロジェクトにはMyDocument.mとMyDocument.hいう2つの新しソースファイルが登録されています。これが、Info.plistでも記載されていた、MyDocumentクラス(NSDocumentクラスのサブクラス)の実装先となります。具体的に言えば、「しんぶんし3」のドキュメントファイルの読み込み(ロード)や保存(セーブ)処理などを記述するソースファイルとなります。MyDocument.hの方は、前回からの定義を引き継げば...
@interface MyDocument : NSDocument
{
NSMutableArray *_list;
}
@end
といった内容になります。「しんぶんし3」のドキュメントファイルの中身は、ズバリ NSMutableArrayとして保存されている_listの中身( 前回示したImageFileオブジェクトの配列)ということになります。
後々必要となるオブジェクトは、先んじてMyDocument.nibの方に登録しておくこともできます。そのため、MyDocument.nibの「File's Owner」は、MyDocumentクラスと定義されており、MyDocumentクラスの「window」アウトレットにはドキュメントウィンドウ(初期の名称はwindow)が、ドキュメントウィンドウの「delegate」には File's Ownerが設定されています。ぜひ一度、Interface Builderのインスペクターで、この両者の関係を調べてみましょう。参考になると思います。
「Cocoa Document-based Application」がどういった物かと言うと、ワープロやペイントソフトなどのアプリケーションを思い浮かべれば良いと思います。特定のファイルをオープンしてウィンドウに表示し、それを編集した後に再度HDへ保存するという一連の処理を提供するアプリケーションのことです。こうしたアプリケーションについては、ある程度「やらなければいけない事柄」が決まっていますので、その部分をCocoa AppKit Framework(クラス)が助けてくれる仕組みが用意されていると思ってください。
助けてくれるのは、NSDocumentController、NSDocument、NSWindowControllerの3つのクラスです。 NSDocumentControllerはアプリケーションに関連付けされたドキュメント(Info.plistに記載されている)を管理し、ドキュメントの新規作成やファイルの読み込み処理を受け持ちます。このクラスのインスタンスはひとつだけ作られており、アプリケーションの裏方さんとして働きます。NSApplicationと似たような役割ですね。
NSDocumentのインスタンスは、ひとつのドキュメントファイルに対してひとつだけ作られます。クラスの実装は、NSDocumentのサブクラスである「MyDocument」を作成し、NSDocumentクラスのメソッドをオーバーライド(書き直す)して行きます。テンプレートから作成されたMyDocument.mには、既にオーバライドすべき(必要であれば)いくつかのメソッドが記述されており、英語のコメントで何の処理をするメソッドなのかが表記されています。とりあえず、以下の5つのメソッドがそれに相当します。
- (id)init
- (NSString *)windowNibName
- (void)windowControllerDidLoadNib:(NSWindowController *) aController
- (NSData *)dataOfType:(NSString *)typeName error:(NSError **)outError
- (BOOL)readFromData:(NSData *)data ofType:(NSString *)typeName
error:(NSError **)outError
3つのうち最後のNSWindowControllerは、ドキュメントを表示するウィンドウのコントロール・オブジェクトです。通常、ひとつのファイルに対しドキュメントウィンドウはひとつ用意されるので、 NSDocumentにひとつのNSWindowControllerのインスタンスが関連付けられます。ただし、大規模で複雑なアプリケーションによっては、ひとつのドキュメントに複数のウィンドウ(ビュー)が必要となる場合があります。そうした場合には、ウィンドウと同数のNSWindowControllerインスタンスが作成されます。
つまり、「 Document-based Application」 においては、 NSDocumentが、モデル・コントローラ・オブジェクトで、NSWindowControllerがビュー・コントローラ・オブジェクトの役割を持ちます。次回は、 MyDocument.mでオーバライドしなければいけない上記メソッドの内容を解説しながら、アプリケーション開発を進めて行きましょう。