8

我试图让键值观察为 NSMutableArray 工作。下面是观察类 MyObservee 的 .h 文件:

@interface MyObservee : NSObject {
    @private int someValue;
    @private NSMutableArray *someArray;
}

@property (readwrite,assign) int someValue;
- (NSMutableArray *)someArray;
@end

MyObserver 类实现了 observeValueForKeyPath:ofObject:change:context:。这是我添加观察者的方法:

MyObservee *moe = [[MyObservee alloc] init];
MyObserver *mobs = [[MyObserver alloc] init];

[moe addObserver:mobs 
      forKeyPath:@"someArray" 
         options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) 
         context:NULL];

[moe.someArray addObject:@"hi there"];

为什么 addObject: 消息没有作为 someArray 键路径的更改触发?我有一种感觉,这里有一些我不完全理解的东西。

4

3 回答 3

13

您需要实现KVC 编程指南中定义的索引数组访问器。然后您必须使用这些访问器来访问数组,KVO 触发将起作用。您还可以调用-mutableArrayValueForKey:并将该数组用于 addObject: 等,然后它将依次调用访问器方法,并且也会发生 KVO 触发。还有用于 NSSet 的 set 访问器,请参见此处此处

例子:

@interface MyClass : NSObject
{
    NSMutableArray *_orders;
}

@property(retain) NSMutableArray *orders;

- (NSUInteger)countOfOrders;
- (id)objectInOrdersAtIndex:(NSUInteger)index;
- (void)insertObject:(id)obj inOrdersAtIndex:(NSUInteger)index;
- (void)removeObjectFromOrdersAtIndex:(NSUInteger)index;
- (void)replaceObjectInOrdersAtIndex:(NSUInteger)index withObject:(id)obj;


@end
于 2009-01-25T06:43:55.073 回答
4

不幸的是,NSArray 类是注意 KVO 兼容的。它们符合 KVC,但您不能像在这里尝试那样直接观察它们。获得此功能的最简单方法是使用 NSArrayController。NSArray 控制器与 KVO 兼容,并会在添加或删除项目时提醒您。在您的示例中,如果您实际更改了数组本身,则会通知您的观察者。例如,如果你做了这样的事情:

[moe setSomeArray:[NSMutableArray array]];

这可能根本不是你想要的 :) 顺便说一句,NSDictionary 实际上是 KVO 兼容的,所以你可以使用它,如果你选择的话。或者你可以编写一个 NSMutableArray 的包装子类,它只是创建一个真正的可变数组作为其后备存储,但只是将所有消息转发给它,除了addObjectremoveObject可以覆盖它以触发通知。

于 2009-01-25T06:17:16.920 回答
3

为什么要将私有数组传递给另一个对象?当您让其他对象处理它时,它就不是那么私密了。

正如 s-bug 所说,您应该实现访问器并使用mutableArrayValueForKey:来改变属性。我补充说,您根本不应该公开该私有数组——您的someArray方法应该返回该数组的不可变副本。

此外,我请您注意 Jason Coco 对 s-bug 答案的评论。套用他的话,您可能应该使用 an作为和NSArrayController之间分离的附加步骤。这是一个非常好的建议,如果你没有具体的理由直接观察房产,你应该接受。(其中一个好处是您可以使用绑定将视图连接到新的数组控制器。)myObserveemyObserver

于 2009-01-25T10:22:18.517 回答