Cocoaバインディングを使って NSMutableArray の内容を NSOutlineView に表示しています。
アプリケーション起動時にモデルクラスの init メソッド内で NSMutableArray を生成し、NSOutlineView に表示する
ところまではうまくいきました。
ところが、アプリケーション起動後にプログラムから NSMutableArray の内容を変更しても、View の表示が更新されません。
キー値監視のドキュメントを参考に、「手動監視」というものを実装してみました。
(バインディングのキーと NSArrya インスタンスの名前は同じにしてあります)
[self willChangeValueForKey:@"aArray"];
// aArray の内容をここで変えたい
[aArray removeAllObjects];
aArray= [NSArray arrayWithArray:bArray];
[self didChangeValueForKey:@"aArray"];
ところが、いっこうに表示は更新されません。
上のコードのような手動監視だけでは不十分なのでしょうか?
また、確認したいこととして、キー値コーディングでは -<key> と -set<key> のようなアクセッサメソッドがない場合でも、
<key> と同じ名前のインスタンス変数にアクセスしてくれる、という認識であっていますか。であれば、インスタンス変数へのアクセスにおいて何か固
有の実装をする必要がない場合は、アクセッサは実装しなくて良いのでしょうか。
よろしくお願いします。
Cocoa binding のときの更新の仕方についてはよくわかりませんが、
通常、NSTableViewやNSOutlineViewのデータを更新し
たときは、
- (void)reloadData
Marks the receiver as needing redisplay, so it will reload the data
for visible cells and draw the new values.
を行わないとviewの表示は更新されません。
> --
> このグループから退会するには、次へメールをお送りください。
> cocoa-dev-jap...@googlegroups.com
> その他のオプションについては以下にアクセスしてください。
> http://groups.google.com/group/cocoa-dev-japan
-----------------------------------------------------
Satoshi Matsumoto <sat...@mac.com>
816-5 Odake, Odawara, Kanagawa, Japan 256-0802
ご返信、ありがとうございます。
reloadData を行いましたが、やはりビューにデータの変化が通知されていないようで、表示が更新されませんでした。
> Satoshi Matsumoto <sato...@mac.com>
上のコードのような手動監視だけでは不十分なのでしょうか?
また、確認したいこととして、キー値コーディングでは -<key> と -set<key> のようなアクセッサメソッドがない場合でも、
<key> と同じ名前のインスタンス変数にアクセスしてくれる、という認識であっていますか。
であれば、インスタンス変数へのアクセスにおいて何か固
有の実装をする必要がない場合は、アクセッサは実装しなくて良いのでしょうか。
KVCに関するKVOの挙動の質問ですが、以下のコードで-setValue:forKeyによるアクセスはアクセサを書かずに機能することが確認でき
ます。
@interface Test : NSObject {
NSString *test;
}
@end
@implementation Test
static NSString *TESTOBSERVE = @"TESTOBSERVE";
-(void)awakeFromNib
{
[self addObserver:self forKeyPath:@"test" options:0
context:TESTOBSERVE];
[self setValue:@"hogehoge" forKey:@"test"];
[self removeObserver:self forKeyPath:@"test"];
}
- (void) observeValueForKeyPath:(NSString *)keyPath ofObject:(id)
object change:(NSDictionary *)change context:(void *)context
{
if (context == TESTOBSERVE) {
NSLog(@"work");
}
else {
[super observeValueForKeyPath:keyPath ofObject:object change:change
context:context];
}
}
@end
バインディングの質問については、何をどこにバインドしているのかが不明瞭で、何が起こっていそうなのかがちょっと把握できませんでした。
もうすこし詳細にわかると、具体的なアドバイスがつくかもしれません。
松本さんがreloadDataについてのアドバイスをしていますが、僕もNSOutlineViewDataSourceを使って
reloadDataで更新してみたらいいんじゃないかと感じます。その場合Bindingは使えませんが。
NSArrayController(テーブルビュー)やNSTreeController(アウトラインビュー)
では、手動通知の方法が異なっていて
・どの位置にあるものが
・どのように変化したか(追加/削除/値の変更)
といった内容をメソッド
willChange:valuesAtIndexes:forKey:
didChange:valuesAtIndexes:forKey:
で通知するようにします。
テーブルビューでの簡単な例をつくってみました。
http://kirika.la.coocan.jp/archive/misc/TableKVO.zip
コードから関係する場所を抜き出してちょっと説明します。
- (IBAction)addRecord:(id)sender
{
NSDictionary *rec;
NSIndexSet *indexSet;
rec = [NSDictionary dictionaryWithObjectsAndKeys:
[NSString stringWithFormat:@"A-%d", [records count]], @"col1",
[NSString stringWithFormat:@"B-%@", [NSDate new]], @"col2", nil];
// この例では最後の位置にひとつ追加するので、追加前の件数=追加する場所
// の位置になる。ここで用意されるindexSetは1件だけのセット
indexSet = [NSIndexSet indexSetWithIndex:[records count]];
// KVO: insert an object
// NSArrayControllerを経由せずに項目を追加して、手動通知
[self willChange:NSKeyValueChangeInsertion valuesAtIndexes:indexSet forKey:@"records"];
[records addObject:rec];
[self didChange:NSKeyValueChangeInsertion valuesAtIndexes:indexSet forKey:@"records"];
}
- (IBAction)removeRecord:(id)sender
{
NSIndexSet *indexes;
// テーブルビューの選択されている行を調べる
indexes = [arrayController selectionIndexes];
if ([indexes count] <= 0) {
return; // no selection
}
[arrayController setSelectionIndexes:[NSIndexSet indexSet]]; // deselect all
// KVO: remove some objects
// NSArrayControllerを経由せずに選択行を削除して、手動通知
[self willChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:@"records"];
[records removeObjectsAtIndexes:indexes];
[self didChange:NSKeyValueChangeRemoval valuesAtIndexes:indexes forKey:@"records"];
}
On Fri, 22 Jan 2010 09:41:35 -0800 (PST), overisland wrote:
> いつもお世話になっています
>
> Cocoaバインディングを使って NSMutableArray の内容を NSOutlineView に表
> 示しています。
> アプリケーション起動時にモデルクラスの init メソッド内で
> NSMutableArray を生成し、NSOutlineView に表示する
> ところまではうまくいきました。
>
> ところが、いっこうに表示は更新されません。
> 上のコードのような手動監視だけでは不十分なのでしょうか?
>
--
kimura wataru
いただいた返信を読んで試行錯誤しているうちに、返信が遅くなってしまい、申し訳ありませんでした。
サンプルコードコードなども載せていただき、大変参考になりました。
結果として、KVOはうまく動作し、モデルのデータ追加や削除が問題なくビューに反映され、望んでいた通りの動作になりました。
かつ、キー値コーディングやKVOなどの知識も深められました。
重ね重ね、返信頂いた皆様に感謝申し上げます。