通过 KVC 访问集合(以保护集合并遵守 KVO)
我有一个 Test 类,其中有一个 Foos 数组。我想提供对 Foos 的访问而不直接暴露 ivar。我正在努力使这个 KVC 兼容(也为 KVO 合规性铺平道路)。我有:
Test.h
@interface Test : NSObject
{
NSMutableArray *foos;
}
@property (readonly, copy) NSMutableArray *foos;
@end
Test.m
- (id) init
{
self = [super init];
if (self != nil)
{
foos = [[NSMutableArray array] retain];
}
return self;
}
- (NSMutableArray*) foos
{
return [self mutableArrayValueForKey:@"foos"];
}
- (NSUInteger)countOfFoos
{
return [foos count];
}
- (id)objectInFoosAtIndex:(NSUInteger)index
{
return [foos objectAtIndex:index];
}
- (NSArray *)foosAtIndexes:(NSIndexSet *)indexes
{
return [foos objectsAtIndexes:indexes];
}
- (void)insertObject:(id)key inFoosAtIndex:(NSUInteger)index
{
[foos insertObject:key atIndex:index];
}
- (void)insertFoos:(NSArray *)foosArray atIndexes:(NSIndexSet *)indexes
{
[foos insertObjects:foosArray atIndexes:indexes];
}
- (void)removeObjectFromFoosAtIndex:(NSUInteger)index
{
[foos removeObjectAtIndex:index];
}
- (void)removeFoosAtIndexes:(NSIndexSet *)indexes
{
[foos removeObjectsAtIndexes:indexes];
}
当客户端尝试添加 Foo 时,这会进入无限循环:
Test *test = [[Test alloc] init];
NSMutableArray *foos = test.foos;
[foos addObject:@"adding object"]; // infinite loop here
我做错了什么?
I have a class Test which has an array of Foos. I want to provide access to the Foos without exposing the ivar directly. I'm trying to make this KVC compliant (also to pave the way for KVO compliance). I have:
Test.h
@interface Test : NSObject
{
NSMutableArray *foos;
}
@property (readonly, copy) NSMutableArray *foos;
@end
Test.m
- (id) init
{
self = [super init];
if (self != nil)
{
foos = [[NSMutableArray array] retain];
}
return self;
}
- (NSMutableArray*) foos
{
return [self mutableArrayValueForKey:@"foos"];
}
- (NSUInteger)countOfFoos
{
return [foos count];
}
- (id)objectInFoosAtIndex:(NSUInteger)index
{
return [foos objectAtIndex:index];
}
- (NSArray *)foosAtIndexes:(NSIndexSet *)indexes
{
return [foos objectsAtIndexes:indexes];
}
- (void)insertObject:(id)key inFoosAtIndex:(NSUInteger)index
{
[foos insertObject:key atIndex:index];
}
- (void)insertFoos:(NSArray *)foosArray atIndexes:(NSIndexSet *)indexes
{
[foos insertObjects:foosArray atIndexes:indexes];
}
- (void)removeObjectFromFoosAtIndex:(NSUInteger)index
{
[foos removeObjectAtIndex:index];
}
- (void)removeFoosAtIndexes:(NSIndexSet *)indexes
{
[foos removeObjectsAtIndexes:indexes];
}
This enters an infinite loop when a client tries to add a Foo:
Test *test = [[Test alloc] init];
NSMutableArray *foos = test.foos;
[foos addObject:@"adding object"]; // infinite loop here
What am I doing wrong?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
访问者不应使用 KVC 来获取正在访问的属性的值;这个想法是 KVC 通过访问器,因为访问器比 KVC 更接近值。
foos 的正确实现应该返回数组的副本(可变或其他)。我将这样做:
我还将公开所有访问器。任何想要改变数组或随机访问特定索引处的元素的操作都可以这样做。它仍然是安全且封装的,因为它们将通过您的访问器,而不是直接访问数组。
除非您在编写代码时不知道将访问哪个密钥,否则实际上没有任何理由自己使用 KVC 协议方法。例如,如果您正在编写 nib 加载器或 Cocoa Bindings 系统,您将使用 KVC。
An accessor should not use KVC to get the value of the property being accessed; the idea is that KVC goes through the accessors, because the accessors are closer to the value than KVC is.
The correct implementation of
foos
should return a copy, mutable or otherwise, of the array. Here's how I'd do it:I would also make all of the accessors public. Anything that wants to mutate the array or randomly access elements at specific indexes can do so that way. It's still safe and encapsulated because they're going through your accessors, not directly accessing the array.
There's not really any reason to use the KVC protocol methods yourself unless you don't know what key you'll access at the time you write the code. For example, if you were writing the nib loader or the Cocoa Bindings system, you would use KVC.
问题是 mutableArrayValueForKey: 返回的代理 NSMutableArray 首先必须获取真实的数组,这是通过“foos”方法完成的。因为它返回一个代理 NSMutableArray,所以它进入了无限循环。一种解决方案是使用另一个名称:
The problem is that the proxy NSMutableArray returned by mutableArrayValueForKey: first has to get the real array, which it does through the "foos" method. Since that's the one that returns a proxy NSMutableArray it enters an infinite loop. One solution is to use another name:
我在这个问题上花了很长时间,并想通过访问器来解决这个问题。我想在答案中为那些进来的人澄清一下。这就是我所做的:
然后显然实现了:
不过必须小心,getFoos似乎是一个(未记录的)KVC访问器,因为这会发送它进入同一个循环。
然后到 KVO:
arrFoos 可以读取更新的、变异的数组(其中将有两个对象),但插入其中不会触发 KVO。在我的冒险经历中,我看到 mutableArrayValueForKey: 返回的不是 NSMutableArray*,而是它的子类,这可能是其原因。
I spent a very long time on this problem and wanted to get this through an accessor. I wanted to clarify in the answer for those coming in. This is what I did:
Then obviously implemented:
Had to be careful though, getFoos appears to be an (undocumented) KVC accessor, because this sends it into the same loop.
Then onto KVO:
arrFoos can read the updated, mutated array (it will have two objects in it), but inserting into it will not fire KVO. Somewhere on my adventures, I saw that the return from mutableArrayValueForKey: doesn't return an NSMutableArray*, but a subclass of it, which might be the cause of it.