键值 - 观察Cocoa中的to-many关系

时间:2009-01-25 05:36:04

标签: cocoa key-value-observing key-value-coding

我正在尝试使用键值观察来为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:message不会作为someArray键路径的更改而触发?我觉得这里有一些我不完全理解的东西。

3 个答案:

答案 0 :(得分:12)

您需要实现KVC programming guide中定义的索引数组访问器。然后,您必须使用这些访问器来访问阵列,KVO触发将起作用。您也可以调用-mutableArrayValueForKey:并使用该数组来添加对象:等等,它将依次调用访问器方法,并且也会发生KVO触发。还有用于NSSets的设置访问器,请参阅herehere

示例:

@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

答案 1 :(得分:4)

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

[moe setSomeArray:[NSMutableArray array]];

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

答案 2 :(得分:3)

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

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

此外,我请你注意Jason Coco对s-bug答案的评论。为了解释他,您应该使用NSArrayController作为myObserveemyObserver之间分离的额外步骤。这是一个非常好的建议,如果您没有具体的理由直接观察该物业,您应该接受它。 (其中的好处是您可以使用Bindings将视图连接到新的阵列控制器。)