Ключ-Значение-Наблюдение отношения ко многим в Какао - PullRequest
8 голосов
/ 25 января 2009

Я пытаюсь заставить наблюдения за ключами работать для NSMutableArray. Ниже приведен файл .h для MyObservee, наблюдаемый класс:

@interface MyObservee : NSObject {
    @private int someValue;
    @private NSMutableArray *someArray;
}

@property (readwrite,assign) int someValue;
- (NSMutableArray *)someArray;
@end

Класс MyObserver реализует наблюденийValueForKeyPath: ofObject: change: context :. Вот как я добавляю наблюдателя:

MyObservee *moe = [[MyObservee alloc] init];
MyObserver *mobs = [[MyObserver alloc] init];

[moe addObserver:mobs 
      forKeyPath:@"someArray" 
         options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld) 
         context:NULL];

[moe.someArray addObject:@"hi there"];

Почему сообщение addObject: не срабатывает как изменение пути к ключу someArray? У меня такое чувство, что я здесь чего-то не понимаю.

Ответы [ 3 ]

12 голосов
/ 25 января 2009

Вам необходимо реализовать средства доступа к индексированным массивам, как определено в Руководстве по программированию KVC . Затем вы должны использовать эти средства доступа для доступа к массиву, и запуск KVO будет работать. Вы также можете вызвать -mutableArrayValueForKey: и использовать этот массив для addObject: и так далее, и он, в свою очередь, будет вызывать методы доступа, и также будет запускаться KVO. Существуют также установленные средства доступа для использования в NSSets, см. здесь и здесь .

Пример:

@interface MyClass : NSObject
{
    NSMutableArray *_orders;
}

@property(retain) NSMutableArray *orders;

- (NSUInteger)countOfOrders;
- (id)objectInOrdersAtIndex:(NSUInteger)index;
- (void)insertObject:(id)obj inOrdersAtIndex:(NSUInteger)index;
- (void)removeObjectFromOrdersAtIndex:(NSUInteger)index;
- (void)replaceObjectInOrdersAtIndex:(NSUInteger)index withObject:(id)obj;


@end
4 голосов
/ 25 января 2009

К сожалению, классы NSArray совместимы с KVO. Они соответствуют KVC, но вы не можете наблюдать их непосредственно, как вы пытаетесь сделать здесь. Самый простой способ получить эту функциональность - использовать NSArrayController. Контроллер NSArray совместим с KVO и предупредит вас, когда элементы будут добавлены или удалены. В вашем примере ваш наблюдатель будет уведомлен, если вы на самом деле изменили сам массив. Например, если вы сделали что-то вроде этого:

[moe setSomeArray:[NSMutableArray array]];

Что, вероятно, совсем не то, что вы хотели :). Кроме того, NSDictionary на самом деле совместим с KVO, так что вы можете использовать его, если захотите. Или вы можете написать подкласс обертки NSMutableArray, который просто создает реальный непостоянный массив в качестве своего резервного хранилища, но просто пересылает ему все сообщения, кроме addObject и removeObject, которые вы можете переопределить для запуска уведомлений.

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

Почему вы передаете свой приватный массив другому объекту? Это не так приватно, когда вы позволяете другим объектам обрабатывать это.

Как сказал s-bug, вы должны реализовать средства доступа и использовать mutableArrayValueForKey: для изменения свойства. Я добавляю, что вы вообще не должны показывать этот закрытый массив - ваш someArray метод должен возвращать неизменную копию массива.

Кроме того, я обращаю ваше внимание на комментарий Джейсона Коко на ответ s-bug. Перефразируя его, вы, вероятно, должны использовать NSArrayController в качестве дополнительного шага разделения между myObservee и myObserver. Это очень хорошее предложение, и если у вас нет конкретной причины для непосредственного наблюдения за объектом, вы должны принять его. (Одним из преимуществ является то, что вы можете использовать привязки для подключения представлений к новому контроллеру массива.)

...