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

发布于 2024-07-12 14:06:02 字数 1182 浏览 14 评论 0原文

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

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

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

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

因此,默认情况下,当我在 Bar 的实例上调用 setValue:forKey: 时,它最终会覆盖NSMutableArray 的实例与 Item 对象的单个实例。 我目前为使其正常工作所做的事情是它变得棘手的地方。 我将数组实例变量重命名为其他名称,假设名称的复数形式:

@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];
    }
}

一切正常! 我确信一定有更好的方法来做到这一点! 我已经通读了《键值编码编程指南》,但我一定错过了一些东西,因为我不清楚数组访问器应该如何工作。 我已经尝试实现 countOf: 和 objectInAtIndex: 正如 KVC 编程指南似乎指出的那样,但这仍然导致我的 NSMutableArray 被 Item 类型的实例覆盖。

I'm trying to work out the "correct" way to handle populating an array with key-value coding for an iPhone app. I've come up with something that works, but it's fairly hackish. Basically I'm parsing an XML document into a set of code-generated models. Let's assume the XML is of this format:

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

On my generated object that represents the Bar element, I have an NSMutableArray defined for the sub-node:

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

So by default when I call setValue:forKey: on an instance of Bar, it ends up overwriting the instance of NSMutableArray with a single instance of the Item object. What I've currently done to get this working is where it gets hacky. I renamed the array instance variable to be something else, let's say the plural form of the name:

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

This causes the default accessor for setValue:forKey: to miss. I then added this method to the Bar implementation:

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

And everything works! I'm sure there must be a better way to do this though! I've read through the Key-Value Coding Programming Guide, but I must be missing something, because I'm unclear as to how things are supposed to work for array accessors. I've tried implementing countOf: and objectInAtIndex: as they KVC Programming guide seems to indicate, but that still results with my NSMutableArray being overwritten with an instance of the Item type.

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

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

发布评论

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

评论(4

红焚 2024-07-19 14:06:02

如果您想对数组使用 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 消息并使用您刚刚定义的方法与实际数组进行交互。

If you want to use KVC properties for an array you should look into the documentation for mutableArrayValueForKey:

Basically with your class:

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

You would define these methods as a minimum, assuming you initialized your array elsewhere:

- (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;
}

Once you've implemented those methods you can call [bar mutableArrayValueForKey:@"items"]. It will return an NSMutableArray proxy object that you can add and remove objects from. That object will in turn generate the appropriate KVO messages and uses the methods you just defined to interact with your actual array.

-小熊_ 2024-07-19 14:06:02

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

As Martin suggests, you cannot directly observe an array to see when items are added or removed. Instead, this would be considered a "to-many" attribute of your Bar object, and you would have to deal with making the KVO assertions yourself. You can do something like this for adding and removing items in bar:

@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

If you wanted to be able to set/replace items directly, you would have to come up with some way to do that yourself. Normally, I would suggest and NSArrayController for this kind of thing, but since you're using the iPhone, you will have to basically create this functionality yourself.

星星的轨迹 2024-07-19 14:06:02

好吧,有两种方法可以解决这个问题:

  1. 在 Bar 类中添加一个“添加项目”方法,在其中传递项目
  2. 确保在执行 KVC 时传递整个项目数组

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

Well, there's 2 ways you can go about it:

  1. Add an "Add Item" method to your Bar class where you pass in the item
  2. Make sure you're passing in the whole array of items when doing KVC

I don't believe there is a way to add an item to an array using KVC.

月野兔 2024-07-19 14:06:02

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

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

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

It is sufficient to call valueForKey:@"item" and the result will be mutable. So you can say:

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

You don't need those other methods unless you're implementing a facade (a key for which there is not mutable instance variable).

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