Об Objective-C / Cocoa Key-Value кодирование и массивы - PullRequest
2 голосов
/ 30 января 2009

Я пытаюсь найти «правильный» способ обработки массива с помощью кодирования значения ключа для приложения iPhone. Я придумал что-то, что работает, но это довольно хакерское. По сути, я разбираю XML-документ на набор сгенерированных моделей. Давайте предположим, что XML имеет этот формат:

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

В моем сгенерированном объекте, который представляет элемент Bar, у меня есть NSMutableArray, определенный для подузла:

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

Таким образом, по умолчанию, когда я вызываю setValue: forKey: для экземпляра Bar, он перезаписывает экземпляр 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];
    }
}

И все работает! Я уверен, что должен быть лучший способ сделать это все же! Я прочитал Руководство по программированию Key-Value Coding, но я должен что-то упустить, потому что мне неясно, как все должно работать для методов доступа к массивам. Я попытался реализовать countOf: и objectInAtIndex: так, как они указывают в руководстве по программированию KVC, но это все равно приводит к тому, что мой NSMutableArray перезаписывается экземпляром типа Item.

Ответы [ 4 ]

3 голосов
/ 30 января 2009

Если вы хотите использовать свойства 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 и использовать только что определенные вами методы для взаимодействия с вашим фактическим массивом.

2 голосов
/ 30 января 2009

Как предполагает Мартин, вы не можете напрямую наблюдать за массивом, чтобы видеть, когда элементы добавляются или удаляются. Вместо этого это будет считаться атрибутом «ко-многим» вашего объекта 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, вам придется в основном создавать эту функцию самостоятельно.

0 голосов
/ 09 июня 2010

Достаточно позвонить valueForKey:@"item", и результат будет изменчивым. Итак, вы можете сказать:

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

Вам не нужны эти другие методы, если вы не реализуете фасад (ключ, для которого нет непостоянной переменной экземпляра).

0 голосов
/ 30 января 2009

Ну, есть 2 способа сделать это:

  1. Добавьте метод «Добавить элемент» в ваш класс Bar, где вы передаете элемент
  2. Убедитесь, что вы передаете весь массив элементов при выполнении KVC

Я не верю, что есть способ добавить элемент в массив с помощью KVC.

...