Iphone 关于Objective-C/Cocoa键值编码和数组

Iphone 关于Objective-C/Cocoa键值编码和数组,iphone,objective-c,cocoa-touch,key-value-coding,Iphone,Objective C,Cocoa Touch,Key Value Coding,我正试图找到一种正确的方法来为iPhone应用程序填充一个带有键值编码的数组。我已经想出了一些有效的方法,但它相当粗糙。基本上,我将XML文档解析为一组代码生成的模型。假设XML的格式如下: <foo> <bar> <item name="baz" /> <item name="bog" /> </bar> </foo> 因此,默认情况下,当我在Bar实例上调用setValu

我正试图找到一种正确的方法来为iPhone应用程序填充一个带有键值编码的数组。我已经想出了一些有效的方法,但它相当粗糙。基本上,我将XML文档解析为一组代码生成的模型。假设XML的格式如下:

<foo>
    <bar>
        <item name="baz" />
        <item name="bog" />
    </bar>
</foo>
因此,默认情况下,当我在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];
    }
}

一切正常!我相信一定有更好的方法来做到这一点!我已经通读了键值编码编程指南,但我肯定遗漏了什么,因为我不清楚数组访问器应该如何工作。正如KVC编程指南所指出的那样,我已经尝试实现countOf:和objectionandex:了,但这仍然会导致我的NSMutableArray被项类型的实例覆盖。

好吧,有两种方法可以实现:

将additem方法添加到传入项的Bar类中 确保在执行KVC时传入整个项目数组
我不相信有办法使用KVC将项目添加到阵列中。

正如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,因此基本上您必须自己创建此功能。

如果您想为阵列使用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消息,并使用刚才定义的方法与实际阵列交互。

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

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

您不需要这些其他方法,除非您正在实现一个facade,一个没有可变实例变量的键。

您正在泄漏内存。。。您已经拥有使用alloc创建的项目,所以不要保留它。啊,谢谢。我肯定我把内存泄漏得到处都是;。没错,无法直接观察数组中项的添加和删除。您必须自己从add和remove方法中实现键值观察调用。因此,KVC文档中关于许多支持的所有讨论都只是为了让我抛开;不,有很多对的支持,你只是无法观察基本数组来查看添加和删除…我对objective-c有点陌生,所以如果这是显而易见的,请原谅我,但我仍然无法调用:[bar setValue:@baz forKey:@item]对吗?问题是,这是解析xml文档的一部分,因此我试图保持在接收对象上设置任意属性的能力。不,您不会这样做,但因为您知道DTD表示允许多个项,所以您将调用addItem,而不是调用setValue。您的另一个选择可能是改用字典并截取设置值。我也会加上一个例子…谢谢,这是最接近我想要实现的。我把所有这些都准备好了,但显然不是在同一时间;。
NSMutableArray* m = [theBar valueForKey:@"item"];
[item addObject: value];