通过 KVC 访问集合(以保护集合并遵守 KVO)

发布于 2024-08-20 14:55:34 字数 1392 浏览 5 评论 0原文

我有一个 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 技术交流群。

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

发布评论

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

评论(3

谜兔 2024-08-27 14:55:34
- (NSMutableArray*) foos
{
    返回 [self mutableArrayValueForKey:@"foos"];
}

访问者不应使用 KVC 来获取正在访问的属性的值;这个想法是 KVC 通过访问器,因为访问器比 KVC 更接近值。

foos 的正确实现应该返回数组的副本(可变或其他)。我将这样做:

- (NSArray *) foos
{
    return [[foos copy] autorelease];
}

我还将公开所有访问器。任何想要改变数组或随机访问特定索引处的元素的操作都可以这样做。它仍然是安全且封装的,因为它们将通过您的访问器,而不是直接访问数组。

除非您在编写代码时不知道将访问哪个密钥,否则实际上没有任何理由自己使用 KVC 协议方法。例如,如果您正在编写 nib 加载器或 Cocoa Bindings 系统,您将使用 KVC。

- (NSMutableArray*) foos
{
    return [self mutableArrayValueForKey:@"foos"];
}

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:

- (NSArray *) foos
{
    return [[foos copy] autorelease];
}

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.

颜漓半夏 2024-08-27 14:55:34

问题是 mutableArrayValueForKey: 返回的代理 NSMutableArray 首先必须获取真实的数组,这是通过“foos”方法完成的。因为它返回一个代理 NSMutableArray,所以它进入了无限循环。一种解决方案是使用另一个名称:

- (NSMutableArray*) mutableFoos
{
    return [self mutableArrayValueForKey:@"foos"];
}

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:

- (NSMutableArray*) mutableFoos
{
    return [self mutableArrayValueForKey:@"foos"];
}
凉风有信 2024-08-27 14:55:34

我在这个问题上花了很长时间,并想通过访问器来解决这个问题。我想在答案中为那些进来的人澄清一下。这就是我所做的:

@property (nonatomic,readonly,getter=getTheFoos) NSMutableArray* foos;

然后显然实现了:

- (NSMutableArray*)getTheFoos {
    return [self mutableArrayValueForKey:@"foos"];
}

不过必须小心,getFoos似乎是一个(未记录的)KVC访问器,因为这会发送它进入同一个循环。

然后到 KVO:

Test* test= [[Test alloc] init];
NSObject* obj= [[NSObject alloc] init];
NSMutableArray* arrTheData= test.foos;

[test.foos insertObject:obj atIndex:0];
[arrFoos insertObject:obj atIndex:0];

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:

@property (nonatomic,readonly,getter=getTheFoos) NSMutableArray* foos;

Then obviously implemented:

- (NSMutableArray*)getTheFoos {
    return [self mutableArrayValueForKey:@"foos"];
}

Had to be careful though, getFoos appears to be an (undocumented) KVC accessor, because this sends it into the same loop.

Then onto KVO:

Test* test= [[Test alloc] init];
NSObject* obj= [[NSObject alloc] init];
NSMutableArray* arrTheData= test.foos;

[test.foos insertObject:obj atIndex:0];
[arrFoos insertObject:obj atIndex:0];

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.

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