ページ

2009年11月30日月曜日

NSTableView にカスタムビューを表示する (5)カスタムセルへ bindings経由でモデルオブジェクトを渡す

このエントリーをブックマークに追加 このエントリーを含むはてなブックマーク

(前回)Cocoaの日々: NSTableView にカスタムビューを表示する (4) カスタムセル続き

NSCell は通常一つのプロパティにバインドするようにできている。カスタムセルでは複数のプロパティを扱いたい。Bindings経由で複数プロパティを渡すには、そのプロパティを持つモデルオブジェクトそのものが渡せれば良い。

(例)Book.title ではなく Book 自体を渡す。そうすれば Book.author にもアクセスできる。

今回はこの課題を扱う。


サンプル作成

前回までのコードに手をいれていく。最初に Interface Builder を立ち上げて Bindings 設定を変更する。



カスタムセルを貼付けている NSTableView の NSTableColumn の Bindings パネルを開き、Model Key Pathを変更する。

前回は上のように特定のプロパティ(Homepage.title)を指していたのをやめ下のように空する。

こうするとプロパティではなくモデルクラス Hompage(のインスタンス)自体に Bindings される。※今回試すまでは Model Key Path が空にできるなんてしらなかった。ただ Controller Key と組み合わせてたんにオブジェクトを探す為のパス(文字列)を構成するだけに使われることを考えると動作することはあたりまえか。

こうするとカスタムセルには Homepage インスタンスが渡されるようになる。

続いて Hompage に copyWithZone: を実装する。
Homepage.m

@implementation Homepage

@synthesize title, image;

- (id)copyWithZone:(NSZone *)zone
{
Homepage* homepage = [[[self class] allocWithZone:zone] init];

homepage.image = [image copyWithZone:zone];
homepage.title = [title copyWithZone:zone];

return homepage;
}

@end


セルの内容を表示する時にその元となるデータはコピーされ、それが表示に使われる。仮に copyWithZone: を実装しないと次の例外が起きて落ちてしまう。


CustomCell[5953:10b] *** -[Homepage copyWithZone:]: unrecognized selector sent to instance 0x1377d0
CustomCell[5953:10b] An uncaught exception was raised




最後にセルで Homepage が取得できているか確認するために描画処理内にデバッグコードを入れておく。

CustomCell.m

- (void)drawWithFrame:(NSRect)cellFrame inView:(NSView *)controlView
{
[[NSColor greenColor] set];
NSRectFill(cellFrame);
[super drawWithFrame:cellFrame inView:controlView];

Homepage* homepage = [self objectValue];
NSLog(@"homepage: title=%@, image=%@", homepage.title, homepage.image);
}



実行

サンプルを実行してみよう。

セルの描画は何もコードを付け足していないので見た目は前回のまま。



デバッグ出力はこう。
CustomCell[5876:10b] homepage: title=SAMPLE-0, image=sample.jpg
CustomCell[5876:10b] setObjectValue: (null)
CustomCell[5876:10b] setObjectValue:
CustomCell[5876:10b] homepage: title=SAMPLE-1, image=sample.jpg
CustomCell[5876:10b] setObjectValue: (null)
CustomCell[5876:10b] setObjectValue:
CustomCell[5876:10b] homepage: title=SAMPLE-2, image=sample.jpg


Homepage のインスタンスがカスタムセルに渡っているのがわかる。意図通りに動いた。


解説

サンプルコードの構成はこんな感じになっている。


NSArrayController を通じて Homepage インスタンスが NSTableColumn へ渡り、最終的に CustomCell へコピーが渡される。CutomCell から見ると何もすることなく自動的に表示対象のデータ objectValue (すなわち Homepageインスタンス)が渡されることになる。このおかげで CustomCell は表示だけに専念できる。




ソースコード

github からどうぞ
CustomCell at 20091130 from xcatsan's SampleCode - GitHub


参考

複製を作るためにNSCopyingプロトコルに準拠する

copyWithZone: の件で参考になった。
最初 copyWithZone: の戻りを次のように autorelease していたらプログラムが吹っ飛んでいた。

Homepage* homepage = [[[[self class] allocWithZone:zone] init] autorelease];

autoreleae してはいけない。

Homepage* homepage = [[[self class] allocWithZone:zone] init];


Mac Dev Center: NSCopying Protocol Reference


- - - - -
Bindings が使えると実装がぐっと楽になる。次回は取得した複数のプロパティをカスタムセルで表示(描画)する方法を考えてみよう。