18

В моей модели у меня есть массив объектов, называемых событиями. Я хочу, чтобы мой контроллер был уведомлен о каждом добавлении нового события в события.Наблюдение Изменения в изменяемом массиве с использованием KVO vs. NSNotificationCenter

Я думал, что хороший способ сделать это было бы использовать шаблон Кво, чтобы получить уведомление, когда события изменения (от нового объекта добавляется)

// AppDelegate 
// events is a NSMutableArray @property/@synthesize etc... 

[appDelagate addObserver:self 
       forKeyPath:@"events" 
        options:NSKeyValueObservingOptionNew 
        context:NULL]; 

Но метод observeValueForKeyPath не было называют и я обнаружил, что массивы не KVO соответствуют :-(

Одним из вариантов является вручную вызвать метод, вызвав willChangeValueForKey для ключевого ресурса

// ViewController 
[self willChangeValueForKey:@"events"]; 
[self.events addObject:event]; 
[self didChangeValueForKey:@"events"]; 

Но это кажется тяжелым, так как я, вероятно, следует также следить за до и после того, как состояние моего массива событий, так что она может быть доступна из метода observeValueForKeyPath.

Один подход может заключаться в использовании стандартного массива (вместо изменяемого) и создания/установки нового экземпляра событий каждый раз, когда я хочу добавить новый объект, или я мог бы создать отдельное свойство, которое отслеживает, сколько элементы находятся в изменяемом массиве (желательно, чтобы вы могли наблюдать @ "events.count").

Другим вариантом является использование NSNotificationCenter. Я также прочитал некоторые ответы, которые предлагают использовать блоки (но я не знаю, с чего начать).

Наконец, могу ли я сохранить экземпляр моего контроллера в своем делегате и просто отправить соответствующее сообщение?

// Delegate 
[myController eventsDidChange]; 

Нечетно ли держать ссылку на контроллер от делегата?

Я изо всех сил пытаюсь понять, как выбрать, какой из них лучше всего использовать, поэтому любые советы по производительности, будущей гибкости кода и передовой практике очень ценятся!

ответ

18

Вы не должны делать прямые публичные свойства для изменяемых коллекций, чтобы избежать их мутации без вашего ведома. NSArray не является ключевым значением, наблюдаемым сам, но ваш один-ко-многим объект@"events" есть. Вот как наблюдать это:

Во-первых, объявить общественную собственность для неизменной коллекции:

@interface Model 
@property (nonatomic, copy) NSArray *events; 
@end 

Затем в реализации назад его с изменяемым Ивар:

@interface Model() 
{ 
    NSMutableArray *_events; 
} 
@end 

и переопределить геттер и сеттер:

@implementation Model 

@synthesize events = _events; 

- (NSArray *)events 
{ 
    return [_events copy]; 
} 

- (void)setEvents:(NSArray *)events 
{ 
    if ([_events isEqualToArray:events] == NO) 
    { 
     _events = [events mutableCopy]; 
    } 
} 

@end 

Если другим объектам необходимо добавить события в свою модель, ey может получить измененный прокси-объект, вызвав -[Model mutableArrayValueForKey:@"events"].

NSMutableArray *events = [modelInstance mutableArrayValueForKey:@"events"]; 
[events addObject:newEvent]; 

Это вызовет уведомления KVO, каждый раз задавая свойство новой коллекцией.Для лучшей производительности и более гранулированного управления, реализуйте остальную часть array accessors.

См. Также: Observing an NSMutableArray for insertion/removal.

+2

Спасибо! mutableArrayValueForKey делает трюк. У вас есть какие-либо подсказки о том, как вы выбираете, какой шаблон использовать (KVO, NotificationCenter, delegate), когда вы хотите установить связь между моделью на контроллер? – MathewS

+0

Я, конечно, чего-то не вижу. Может кто-нибудь объяснить, где setEvents будет вызываться, если кто-то должен был добавить или insertObject: atIndex: объект для изменяемого массива поддержки? –

0

согласно docs on accessor methods, вы должны реализовать:

- (void)addEventsObject:(Event*)e 
{ 
    [_events addObject:e]; 
} 

- (void)removeEventsObject:(Event*)e 
{ 
    [_events removeObject:e]; 
} 

Затем КВО будет срабатывать уведомления, когда их называют.

Смежные вопросы