我看到一些古怪的行爲與可可的KVC/KVO和綁定。我有一個NSArrayController
對象,其「內容」綁定到NSMutableArray
,並且我有一個控制器在NSArrayController
上註冊爲arrangedObjects
屬性的觀察者。使用此設置,我希望每次修改陣列時都會收到KVO通知。但是,KVO通知似乎只發送一次;數組第一次被修改。KVC/KVO和綁定:爲什麼我只收到一個更改通知?
我在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通知僅在第一次發送(並且在應用程序退出時再次發送)。爲什麼會這樣呢?
更新:
感謝orque您指出我應該結合我NSArrayController
的contentArray
,不只是它的content
。上面貼的代碼工作,一旦此更改:
// bind the arrayController to the array
[arrayController bind:@"contentArray" // <-- the change was made here
toObject:self
withKeyPath:@"mutableArray"
options:0];
+1,並感謝您的一個非常詳細的答案。我把我的綁定改爲「contentArray」而不是「內容」,所有事情都像魅力一樣。至於通過控制器更改陣列:這是一個簡化的例子。在我的真實應用程序中,該數組是模型對象上的一個屬性,並通過另一個進程進行修改。如果我要使用arrayController來修改我的對象,我的Model類將需要耦合到我的Controller類,這完全違背了MVC模式。 – 2009-08-21 21:14:38
按鈕動作是'add:',而不是'addObject:'(它會添加按鈕!)。 – 2009-08-21 23:11:24