观察 Cocoa 中的键值对多关系

发布于 2024-07-12 14:19:42 字数 759 浏览 15 评论 0 原文

我正在尝试让键值观察适用于 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 键路径的更改而触发? 我有一种感觉,这里有一些我不完全理解的地方。

I am trying to get key-value-observing to work for an NSMutableArray. Below is the .h file for MyObservee, the observed class:

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

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

The class MyObserver implements observeValueForKeyPath:ofObject:change:context:. Here is how I add the observer:

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"];

How come the addObject: message isn't triggering as a change to the someArray key path? I have a feeling there's something I don't fully understand here.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

仅此而已 2024-07-19 14:19:42

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

例子:

@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

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:

@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
↘人皮目录ツ 2024-07-19 14:19:42

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

[moe setSomeArray:[NSMutableArray array]];

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

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:

[moe setSomeArray:[NSMutableArray array]];

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 and removeObject which you could override to trigger notifications.

半透明的墙 2024-07-19 14:19:42

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

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

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

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—your someArray 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 between myObservee and myObserver. 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.)

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文