2

我正在尝试找出“正确”的方法来处理使用 iPhone 应用程序的键值编码填充数组。我想出了一些可行的方法,但它相当hackish。基本上,我将 XML 文档解析为一组代码生成的模型。让我们假设 XML 是这种格式:

<foo>
    <bar>
        <item name="baz" />
        <item name="bog" />
    </bar>
</foo>

在我生成的代表 Bar 元素的对象上,我为子节点定义了一个 NSMutableArray:

@interface Bar : NSObject {
    NSMutableArray *item;
}
@end

因此,默认情况下,当我在 Bar 的实例上调用 setValue:forKey: 时,它最终会用 Item 对象的单个实例覆盖 NSMutableArray 的实例。我目前为使其正常工作所做的工作是它变得很糟糕的地方。我将数组实例变量重命名为别的东西,让我们说名称的复数形式:

@interface Bar : NSObject {
    NSMutableArray *items;
}
@end

这会导致 setValue:forKey: 的默认访问器丢失。然后我将此方法添加到 Bar 实现中:

- (void)setValue:(id)value forUndefinedKey:(NSString *)key {
    if([key isEqualToString:@"item"]) {
        if(items == nil) {
            items = [[NSMutableArray alloc] init];
            [items retain];         
        }
        [items addObject:value];
    }
}

一切正常!我相信一定有更好的方法来做到这一点!我已经通读了 Key-Value Coding Programming Guide,但我一定遗漏了一些东西,因为我不清楚数组访问器应该如何工作。我已经尝试实现 countOf: 和 objectInAtIndex: 他们 KVC 编程指南似乎表明,但这仍然会导致我的 NSMutableArray 被 Item 类型的实例覆盖。

4

4 回答 4

3

如果你想对数组使用 KVC 属性,你应该查看文档mutableArrayValueForKey:

基本上与你的班级:

@interface Bar : NSObject {
    NSMutableArray *items;
}
@end

假设您在其他地方初始化了数组,您将至少定义这些方法:

- (void)insertObject:(id)object inItemsAtIndex:(NSUInteger)index {
    [items insertObject:object atIndex:index];
}

- (void)removeObjectFromItemsAtIndex:(NSUInteger)index {
    [items removeObjectAtIndex:index];
}

- (NSArray *)items {
    /* depending on how pedantic you want to be
       possibly return [NSArray arrayWithArray:items] */
    return items;
}

一旦你实现了这些方法,你就可以调用[bar mutableArrayValueForKey:@"items"]. 它将返回一个NSMutableArray代理对象,您可以从中添加和删除对象。该对象将依次生成适当的 KVO 消息并使用您刚刚定义的方法与您的实际数组进行交互。

于 2009-01-30T06:19:22.703 回答
2

正如 Martin 建议的那样,您不能直接观察数组来查看添加或删除项目的时间。相反,这将被视为 Bar 对象的“多对多”属性,您必须自己处理 KVO 断言。您可以执行以下操作来添加和删除栏中的项目:

@interface Bar : NSObject
{
    NSMutableArray *items;
}
-(void)addItem:(id)item;
-(void)removeItem:(id)item;
@end

@implementation Bar
-(id)init
{
    if( (self = [super init]) ) {
        items = [[NSMutableArray alloc] init];
    }
    return self;
}

-(void)addItem:(id)item
{
    NSParameterAssert(item);
    NSIndexSet *iset = [NSIndexSet indexSetWithIndex:[items count]];
    [self willChange:NSKeyValueChangeInsertion valuesAtIndexes:iset forKey:@"items"];
    [items addObject:item];
    [self didChange:NSKeyValueChangeInsertion valuesAtIndexes:iset forKey:@"items"];
}

-(void)removeItem:(id)item
{
    NSParameterAssert(item);
    NSIndexSet *iset = [NSIndexSet indexSetWithIndex:[items indexForObject:item]];
    [self willChange:NSKeyValueChangeRemoval valuesAtIndexes:iset forKey:@"items"];
    [items removeObject:item];
    [self didChange:NSKeyValueChangeRemoval valuesAtIndexes:iset forKey:@"items"];
}
@end

如果您希望能够直接设置/替换项目,您必须自己想出一些方法来做到这一点。通常,我会建议NSArrayController这种事情,但由于您使用的是 iPhone,因此您基本上必须自己创建此功能。

于 2009-01-30T02:43:46.913 回答
0

好吧,有两种方法可以解决:

  1. 在您传入项目的 Bar 类中添加“添加项目”方法
  2. 确保在执行 KVC 时传入整个项目数组

我不相信有一种方法可以使用 KVC 将项目添加到数组中。

于 2009-01-30T02:05:18.050 回答
0

调用就足够了valueForKey:@"item",结果将是可变的。所以你可以说:

NSMutableArray* m = [theBar valueForKey:@"item"];
[item addObject: value];

除非您正在实现外观(没有可变实例变量的键),否则您不需要这些其他方法。

于 2010-06-09T18:07:12.770 回答