观察 Cocoa 中的键值对多关系
我正在尝试让键值观察适用于 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 键路径的更改而触发? 我有一种感觉,这里有一些我不完全理解的地方。
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
您需要实现 KVC 编程指南。 然后,您必须使用这些访问器来访问数组,KVO 触发才会起作用。 您还可以调用 -mutableArrayValueForKey: 并使用该数组来 addObject: 等,它将依次调用访问器方法,并且也会发生 KVO 触发。 还有用于 NSSet 的设置访问器,请参阅 此处 和 此处。
例子:
You need to implement the indexed array accessors as defined in the KVC programming guide. Then you must use those accessors to access the array and the KVO triggering will work. You can also call -mutableArrayValueForKey: and use that array to addObject: and such and it will in turn call the accessor methods and the KVO triggering will occur as well. There are also set accessors for use in for NSSets, see here and here.
Example:
不幸的是,NSArray 类不符合 KVO 标准。 它们符合 KVC 标准,但您无法像在这里尝试那样直接观察它们。 获得此功能的最简单方法是使用 NSArrayController。 NSArray 控制器符合 KVO 标准,并且会在添加或删除项目时提醒您。 在您的示例中,如果您实际上更改数组本身,您的观察者将会收到通知。 例如,如果你做了这样的事情:
这可能根本不是你想要的:) 顺便说一句,NSDictionary 实际上是 KVO 兼容的,所以你可以使用它,如果你选择的话。 或者,您可以编写 NSMutableArray 的包装子类,它只创建一个真正的可变数组作为其后备存储,但仅将所有消息转发给它,除了您可以重写的
addObject
和removeObject
之外来触发通知。Unfortunately, The NSArray classes are note KVO compliant. They are KVC compliant, but you can't observe them directly like you're trying to do here. The easiest way to get this functionality would be to use an NSArrayController. The NSArray controller is KVO compliant and will alert you when items are added or removed. In your example, your observer would be notified if you actually changed the array itself. For instance, if you did something like this:
Which is probably not what you wanted at all :) Just as an aside, NSDictionary is actually KVO compliant so you could use that, if you chose. Or you could write a wrapper subclass of NSMutableArray that just creates a real mutable array as its backing store but just forwards on all messages to it except
addObject
andremoveObject
which you could override to trigger notifications.为什么要将私有数组传递给另一个对象? 当您让其他对象处理它时,它就不那么私密了。
正如 s-bug 所说,您应该实现访问器并使用 mutableArrayValueForKey: 来改变属性。 我补充说,您根本不应该公开该私有数组 - 您的
someArray
方法应该返回该数组的不可变副本。此外,我提请您注意 Jason Coco 对 s-bug 答案的评论。 套用他的话,您可能应该使用
NSArrayController
作为分离myObservee
和myObserver
之间的附加步骤。 这是一个非常好的建议,如果你没有具体的理由直接观察房产,你应该采纳它。 (其中一个好处是您可以使用绑定将视图连接到新的数组控制器。)Why are you passing your private array to another object? It's not so private when you let other objects handle it.
As s-bug said, you should implement the accessors and use
mutableArrayValueForKey:
to mutate the property. I add that you should not be exposing that private array at all—yoursomeArray
method should return an immutable copy of the array.Furthermore, I call your attention to Jason Coco's comment on s-bug's answer. To paraphrase him, you should probably use an
NSArrayController
as an additional step of separation betweenmyObservee
andmyObserver
. This is a very good suggestion, and if you don't have a specific reason to directly observe the property, you should take it. (Among the benefits is that you can then use Bindings to connect views to the new array controller.)