Подтвердить что ты не робот

Наблюдение изменений в изменяемом массиве с использованием KVO vs. NSNotificationCenter

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

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

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

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

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

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

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

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

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

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

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

// Delegate
[myController eventsDidChange];

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

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

4b9b3361

Ответ 1

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

Сначала объявите общедоступное свойство для неизменяемой коллекции:

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

Затем в вашей реализации верните его с помощью изменяемого ivar:

@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

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

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

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

См. также: Наблюдение NSMutableArray для вставки/удаления.

Ответ 2

В docs по методам доступа, вы должны реализовать:

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

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

Затем KVO будет запускать уведомления при их вызове.