私はCocoaのKVC/KVOとバインディングでいくつか風変わりな動作を見ています。私はNSArrayController
オブジェクトを持っていて、その内容はNSMutableArray
に結び付けられていて、コントローラはarrangedObjects
というオブザーバとしてNSArrayController
に登録されています。この設定では、配列が変更されるたびにKVO通知を受け取る予定です。ただし、KVO通知は一度だけ送信されるように見えます。配列が変更されたのは初めてです。KVC/KVOとバインディング:なぜ私は変更通知を1つだけ受け取っていますか?
Xcodeで新しい「Cocoa Application」プロジェクトを設定して問題を説明しました。ここに私のコードは次のとおりです。
BindingTesterAppDelegate.h
#import <Cocoa/Cocoa.h>
@interface BindingTesterAppDelegate : NSObject <NSApplicationDelegate>
{
NSWindow * window;
NSArrayController * arrayController;
NSMutableArray * mutableArray;
}
@property (assign) IBOutlet NSWindow * window;
@property (retain) NSArrayController * arrayController;
@property (retain) NSMutableArray * mutableArray;
- (void)changeArray:(id)sender;
@end
BindingTesterAppDelegate.m
#import "BindingTesterAppDelegate.h"
@implementation BindingTesterAppDelegate
@synthesize window;
@synthesize arrayController;
@synthesize mutableArray;
- (void)applicationDidFinishLaunching:(NSNotification *)notification
{
NSLog(@"load");
// create the array controller and the mutable array:
[self setArrayController:[[[NSArrayController alloc] init] autorelease]];
[self setMutableArray:[NSMutableArray arrayWithCapacity:0]];
// bind the arrayController to the array
[arrayController bind:@"content" // see update
toObject:self
withKeyPath:@"mutableArray"
options:0];
// set up an observer for arrangedObjects
[arrayController addObserver:self
forKeyPath:@"arrangedObjects"
options:0
context:nil];
// add a button to trigger events
NSButton * button = [[NSButton alloc]
initWithFrame:NSMakeRect(10, 10, 100, 30)];
[[window contentView] addSubview:button];
[button setTitle:@"change array"];
[button setTarget:self];
[button setAction:@selector(changeArray:)];
[button release];
NSLog(@"run");
}
- (void)changeArray:(id)sender
{
// modify the array (being sure to post KVO notifications):
[self willChangeValueForKey:@"mutableArray"];
[mutableArray addObject:[NSString stringWithString:@"something"]];
NSLog(@"changed the array: count = %d", [mutableArray count]);
[self didChangeValueForKey:@"mutableArray"];
}
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
{
NSLog(@"%@ changed!", keyPath);
}
- (void)applicationWillTerminate:(NSNotification *)notification
{
NSLog(@"stop");
[self setMutableArray:nil];
[self setArrayController:nil];
NSLog(@"done");
}
@end
そして、ここで出力されます:
load
run
changed the array: count = 1
arrangedObjects changed!
changed the array: count = 2
changed the array: count = 3
changed the array: count = 4
changed the array: count = 5
stop
arrangedObjects changed!
done
あなたが見ることができるように、 KVO通知は初めて送信されます(アプリケーションが終了するともう一度送信されます)。なぜこれが当てはまるのでしょうか?
アップデート:私は私のNSArrayController
のcontentArray
に結合する必要があることを指摘しorqueから
おかげだけではなく、そのcontent
。上記掲載のコードは、すぐにこの変更が行われたとして、働く:
// bind the arrayController to the array
[arrayController bind:@"contentArray" // <-- the change was made here
toObject:self
withKeyPath:@"mutableArray"
options:0];
+1と非常に詳細な回答ありがとうございます。私は "content"ではなく "contentArray"へのバインディングを変更し、すべてが魅力的に機能しました。コントローラを介してアレイを変更する場合:これは単純化された例です。実際のアプリケーションでは、配列はモデルオブジェクトのプロパティであり、別のプロセスによって変更されます。 arrayControllerを使用してオブジェクトを変更する場合、Modelクラスをコントローラクラスに結合する必要があります。コントローラクラスはMVCパターンと完全に対応しています。 –
ボタンのアクションは 'add:'であり、 'addObject:'ではなく、ボタンを追加します! –