● Carbon視点でCocoa探求(2007/11/05)

  このニュースは、MOSAの会員にのみ配布されているデベロッパー向けの
  デジタルマガジンMOSADeNのに掲載された記事です。ほぼ一ヶ月遅れで
  ここに掲載されて行きます

 〜 File's Owne 〜


今回も引き続き、Cocoaプロジェクトに含まれるMainMenu.nibとMyDocument.nibの中身を調査します。File's OwnerとFirst Responderアイコンは具体的にどんな役割を受け持っているのでしょうか?

CarbonプログラマがInterface BuilderでCocoaプロジェクト用のNibファイルを編集しようとした時、最初に目に入るのがFile's OwnerとFirst Responderの2つのアイコンです。
Carbon用Nibファイルにはそのようなアイコンはありませんので「これは何だ?」というわけで、入門書を引っ張り出して調べ始めます。ところが、筆者もそうでしたが、これらのアイコンの名称が混乱を招き(First Responderは別の意味で検索されたりする)明確な答えが見つからずに悩むことになります。

Interface BuilderのInstancesタブに並んでいるアイコンのほとんどは、それぞれが何らかのクラスから生成されたオブジェクトを表しており、アプリケーションにNibファイルが読み込まれた時にインスタンスが生成され実体化します。WindowとMainMenuアイコンは、それぞれがNSWindowクラスとNSMenuクラスのオブジェクト(View Object)です。ところが、File's OwnerやFirst Responderはそれ自体からオブジェクト(インスタンス)が生成されることはなく、まったく別の役割を受け持っています。まず先んじて、File's Ownerについて詳しく調べてみましょう。

File's Ownerは、Nibファイルが読み込まれた時に、その中で定義されているオブジェクトと、既にメモリ内に確保されている別オブジェクト「Owner Object」とを接続する(関係づける)ために用意されています。つまり重要なことは、Nibファイルが読み込まれても、File's Ownerに設定してあるクラスのオブジェクトは生成されないと言う点です。例えば、NSBundleクラスには、Nibファイルを読み込み、そこに定義されているすべてのオブジェクトを生成するloadNibNamedと言うクラスメソッドがあります。

(BOOL)loadNibNamed:(NSString *)nibName owner:(id)owner;

これを使い、自作MyObjectクラスのinitメソッドにおいて、MyObject.nibに定義されているオブジェクトをすべて呼び出す(生成する)には、以下のように記述します。

- (id)init
{
  self = [super init];
  [NSBundle loadNibNamed:@"About" owner:self];
  return self;
}

selfは、作成(alloc)されたMyObjectクラスのオブジェクト自身です。そしてメッセージとしてOwner Objectを渡している箇所が、owner:selfの部分です。

selfは先んじて生成されており、MyObject.nib内にそのオブジェクトを定義する必要はありません。続いて、MyObjectのメソッドからMyObject.nib内に定義してあるオブジェクト(ウィンドウやコントローラ)を参照しなければいけないとすると、Interface Builderで2つのオブジェクト間を接続する(線を引く)必要があります。ところが、Nibファイル側にはMyObjectアイコンがありませんので、物理的に接続することは不可能となります。

そのため、その代用として使われるのがFile's Ownerアイコンなのです。上記の例では、InspectorでFile's OwnerのCustum ClassにMyObjectクラスを指定してから、他のアイコンと同様にオブジェクト間の接続に利用します。アイコンがアプリケーション形状であることから分かるように、 MainMenu.nibのFile's OwnerのCustum ClassにはNSApplicationが割り当てられています。つまり、File's Ownerアイコンがアプリケーションが生成したNSApplicationオブジェクトの代用として使われるわけです。

例を見てみます。MainMenuから「Quit NewApplication」アイテムを選び、InspectorでConnectionsのTraget/Actionを確認すると、アクションとしてterminate:がアサインされています。terminate:はNSApplicationのメソッドであり、アプリケーションを終了させる処理を実行します。Carbonで言えば、QuitApplicationEventLoop()やExitToShell()に相当します。Interface Builderでオブジェクトの接続を見ると「Quit NewApplication」アイテムからFile's Ownerアイコンへと線が引かれていることが分かります。

それではと言うことで、試しにCustum ClassのNSApplicationをNSObjectなどに変更してみます。すると、何度も「接続が切れるぞ!」というアラートが表示されますが、その警告を無視して実行すると、File's Ownerのアイコン形状がアプリケーションから青色立方体に変わります。この状態でアプリケーションを起動すると、もはやNSApplicationオブジェクトとの接続関係が消えてしまっているので、Quitメニューは働かず、アプリケーションを終了させることができません。

Interface Builderでは、こうしたリンク切れの発生(不注意による)に対しては厳重な注意が必要なのですが、それはさておき、今度はMyDocument.nibの方のFile's Ownerも見てみましょう。MyDocument.nibのFile's Ownerアイコンには、NSDocumentのサブクラスであるMyDocumentクラスが割り当てられています。そして、ソースコードのMyDocument.hにはそのクラス定義が、MyDocument.mにはオーバライト(書き換え)するNSDocumentメソッド(雛形)が記述されています。

ソースコードの解説は省略しますが、MyDocument.nibはファイルメニューから「新規」や「開く」が選択される度に読み込まれて、そこに定義されているオブジェクトを生成します。MyDocument.nibにはNSWindowオブジェクトがひとつ登録されていますが、InspectorのConnectionsで調べると、File's OwnerのwindowアウトレットにWindow(NSWindow)が、WindowのdelegateアウトレットにFile's Owner(MyDocument)が接続されていることが分かります。これが、MyDocument.nibファイルが読み込まれた後に、既存オブジェクトとの接続関係を確立するための情報となっています。

このような仕組みを見ると、どうも「File's Owner」というアイコン名は不適切でユーザを混乱させているような気がします。単純に「Owner Object」とするか、Custum Classで選択されているクラス名(Owner Objectのクラス名)が表示される方が分かりやすいと思います。例えば、MainMenu.nibならNSApplcication、MyDocument.nibであればMyDocumentですね。ただし、後で作成したオブジェクトアイコンとは役目が異うわけですから、立方体の色を変えておけば(赤色とかに)より差別化しやすいのではないでしょうか?

次回は、もうひとつの謎のアイコンFirst Responderの仕組みを調べてみましょう。こちらも、File's Owner同様「線を引く相手がいないぞ、さてどうしよう?」と言う疑問点が重要なポイントとなっています(笑)。


copyright 2007 Ottimo, Inc. All rights reserved
無断転載・引用禁止