2010-11-25

Cocoa Bindings の使い方

追記@2010-11-30

Cocoa Bindings の使い方については以下の後続記事も参照のこと。

ブログの記事一覧を表示するようなアプリでは、記事一覧のデータは、配列(のような何か)に蓄えることになるし、画面の表示は表形式(に似た何か)を使うことになるだろう。

Cocoa アプリでこれをシンプルに実現すると、配列 (NSMutableArray) に蓄えられたデータをテーブルビュー (NSTableView) に表示するものになる。MVC アーキテクチャで言うなら、配列がモデル(正確には配列に蓄えられたオブジェクトがモデル)で、テーブルビューが(その名の通り)ビューになる。

NSTableView にデータを表示させる場合、二通りの方法がある。1 つは、NSTableView のデータソースとなるクラスを定義する方法。具体的には、AppController というようなクラスを定義し(MVC の C)、そこで以下の 3 つのメソッドを定義するというもの。

  • - numberOfRowsInTableView:
  • - tableView:objectValueForTableColumn:row:
  • - tableView:setObjectValue:forTableColumn:row:

3 つ目のメソッドは表示のみのアプリなら必要ない。

この方法の欠点は、NSMutableArray の内容を NSTableView における表示と同期させるコードは、どれも良く似ているものになることだ。

良く似たものになるなら、その仕組みを共通化してフレームワークが提供してくれればありがたい。もちろん、そのためにはある種の「抽象化」が必要になり、利用に際しては一定の「作法」に従わなければならない。この「共通化された仕組み」が Cocoa Bindings であり、「抽象化」が KVC (Key-Value Coding)、「作法」が KVO (Key-Value Observing) ということになる。

サンプルアプリ

今回、サンプルとして作ったアプリのスクショがこれ(→)だ。機能的には(意匠的にも)ヒレガス本の Chapter 8 で作るもの(→ 「MVC と Cocoaバインディング」参照)と同等だが、こちらは、コードとして書いたのはモデルとなる 2 つのクラスのみで、ビューは当然として、コントローラも Cocoa フレームワークの提供するものだけで作られている。

モデル

まずはモデルを構成する 2 つのクラスを示す。これら 2 つは、Atom 形式のフィードから生成することを想定したものだ。Feed オブジェクトが Entry オブジェクトの配列を抱えるようになっている。

Entry の定義
//  Entry.h
#import <Cocoa/Cocoa.h>

@interface Entry : NSObject {
    NSString *title;
    NSDate *updated;
}

@property (readwrite, retain) NSString *title;
@property (readwrite, retain) NSDate *updated;

@end
//  Entry.m
#import "Entry.h"

@implementation Entry
- (id)init
{
    [super init];
    title = @"Hi!";
    updated = [[NSDate date] retain];
    return self;
}

- (void)dealloc
{
    [updated release];
    [title release];
    [super dealloc];
}

@synthesize title, updated;

- (void)setTitle:(NSString *)newTitle
{
    if (newTitle == title) return;
    [title release];
    title = [newTitle retain];
    self.updated = [[NSDate date] retain];
}

@end
Feed の定義
//  Feed.h
#import <Cocoa/Cocoa.h>

@interface Feed : NSObject {
    NSString *title;
    NSDate *updated;
    NSMutableArray *entries;
    int count;
}

@property (readwrite, retain) NSString *title;
@property (readwrite, retain) NSDate *updated;
@property (readwrite, retain) NSMutableArray *entries;
@property (readwrite) int count;


@end
//  Feed.m
#import "Feed.h"
#import "Entry.h"

@implementation Feed
- (id)init
{
    [super init];
    title = @"My Feed";
    updated = [[NSDate date] retain];
    entries = [[NSMutableArray alloc] init];
    [entries addObject:[[Entry alloc] init]];
    count = [entries count];
    return self;
}

- (void)dealloc
{
    [entries release];
    [updated release];
    [title release];
    [super dealloc];
}

@synthesize title, updated, entries;

- (void)setEntries:(NSMutableArray *)newArray
{
    if (newArray == entries) return;
    [entries release];
    entries = [newArray retain];
    self.count = [entries count];
}

@synthesize count;
@end
コントローラ

コントローラには NSObjectControllerNSArrayController を 1 つずつ使っている。これらのコントローラは Interface Builder から NIB (今は XIB)ファイルの中にインスタンス化し、設定を変更しているだけだ。コードは一切、書いていない。

これらコントローラの設定で肝となるのは、それぞれのコントローラが保持することになるモデルクラスとの対応づけだ。NSObjectController は 上述のFeed クラスのオブジェクトを保持する。NSArrayControllerEntry クラスのオブジェクトを生成し(Add ボタンのアクション)、消滅させる(Delete ボタンのアクション)。ただし、Entry オブジェクトたちを保持するのは Feed が抱えた配列だ。このため、NSArrayControllerFeed オブジェクトに対して要素となる Entry オブジェクトの追加、編集、削除を指示する必要がある。このとき用いられるのが Cocoa Bindings だ。

NSArrayController は配列を抱えた NSObjectController にバインドされることになる。

ビュー

スクショを見ればわかるように、いくつかのテキストフィールド(いずれも編集不可にしてある)とテーブルビュー(タイトル欄のみ編集可)、および 2 つのボタンから構成されている。いずれも Cocoa フレームワーク標準のビューたちだ。

テキストフィールドおよびテーブルビュー(のセル)は、Cocoa Bindings によって、2 つのコントローラのプロパティを経由してモデルと結びつけられている。このため、モデル(のプロパティ)が変更されれば、KVO の通知により自動的に変更がビューに反映されることになり、ビューによる変更はコントローラを経由してモデルに反映されるようになっている。

まとめ

MVC のうちモデルとなるクラスを書くだけで後は、Interface Builder の操作でアプリが作れてしまう。標準の部品(ビューとコントローラ)を使うアプリであれば簡単にできる。ただし、Interface Builder を使って Cocoa Bindings の設定するのには、ちょっと慣れが必要だ。似たような設定項目が多く、設定する場所を間違えたら、まったく動かない。今日もそれでかなり苦労した。

参考文献

詳解 Objective-C 2.0
荻原 剛志
ソフトバンククリエイティブ ( 2008-05-28 )
ISBN: 9784797346800
Cocoa Programming for Mac OS X
Aaron Hillegass
Addison-Wesley Professional ( 2008-05-15 )
ISBN: 9780321503619

関連リンク

関連記事

0 件のコメント:

コメントを投稿