Соответствие KVO

Для рассмотрения KVO-совместимым для определенного свойства, класс должен гарантировать следующее:

Существует два метода для обеспечения уведомлений изменения, испускаются. Автоматическая поддержка предоставлена NSObject и по умолчанию доступно для всех свойств класса, которые являются значением ключа, кодирующим совместимый. Как правило, если Вы следуете за стандартным кодированием Какао и соглашениями о присвоении имен, можно использовать автоматические уведомления изменения — Вы не должны писать дополнительный код.

Ручное уведомление изменения обеспечивает дополнительное управление, когда уведомления испускаются, и требует дополнительного кодирования. Можно управлять автоматическими уведомлениями для свойств подкласса путем реализации метода класса automaticallyNotifiesObserversForKey:.

Автоматическое уведомление изменения

NSObject обеспечивает базовое внедрение автоматического уведомления изменения значения ключа. Автоматическое уведомление изменения значения ключа сообщает наблюдателям изменений, внесенных с помощью значения ключа совместимые средства доступа, а также методы кодирования значения ключа. Автоматическое уведомление также поддерживается объектами прокси набора, возвращенными, например, mutableArrayValueForKey:.

Примеры, показанные в Перечислении 1, приводят к любым наблюдателям свойства name быть уведомленным относительно изменения.

  Примеры перечисления 1 вызовов метода, заставляющих уведомления изменения KVO испускаться

// Call the accessor method.
[account setName:@"Savings"];
 
// Use setValue:forKey:.
[account setValue:@"Savings" forKey:@"name"];
 
// Use a key path, where 'account' is a kvc-compliant property of 'document'.
[document setValue:@"Savings" forKeyPath:@"account.name"];
 
// Use mutableArrayValueForKey: to retrieve a relationship proxy object.
Transaction *newTransaction = <#Create a new transaction for the account#>;
NSMutableArray *transactions = [account mutableArrayValueForKey:@"transactions"];
[transactions addObject:newTransaction];

Ручное уведомление изменения

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

Класс, реализующий ручное уведомление, должен переопределить NSObject реализация automaticallyNotifiesObserversForKey:. Возможно использовать и автоматические и ручные уведомления наблюдателя в том же классе. Для свойств, выполняющих ручное уведомление, реализацию подкласса automaticallyNotifiesObserversForKey: должен возвратиться NO. Реализация подкласса должна вызвать super для любых нераспознанных ключей. Пример в Перечислении 2 включает ручное уведомление для openingBalance свойство, позволяющее суперкласс определить уведомление для всех других ключей.

  Реализация перечисления 2 В качестве примера automaticallyNotifiesObserversForKey:

+ (BOOL)automaticallyNotifiesObserversForKey:(NSString *)theKey {
 
    BOOL automatic = NO;
    if ([theKey isEqualToString:@"openingBalance"]) {
        automatic = NO;
    }
    else {
        automatic = [super automaticallyNotifiesObserversForKey:theKey];
    }
    return automatic;
}

Для реализации ручного уведомления наблюдателя Вы вызываете willChangeValueForKey: прежде, чем изменить значение, и didChangeValueForKey: после изменения значения. Пример в Перечислении 3 реализует ручные уведомления для openingBalance свойство.

  Метод доступа перечисления 3 В качестве примера, реализовывая ручное уведомление

- (void)setOpeningBalance:(double)theBalance {
    [self willChangeValueForKey:@"openingBalance"];
    _openingBalance = theBalance;
    [self didChangeValueForKey:@"openingBalance"];
}

Если значение изменилось, можно минимизировать передающие ненужные уведомления первой проверкой. Пример в Перечислении 4 тестирует значение openingBalance и только обеспечивает уведомление, если оно изменилось.

Перечисление 4  , Тестирующее значение на изменение прежде, чем обеспечить уведомление

- (void)setOpeningBalance:(double)theBalance {
    if (theBalance != _openingBalance) {
        [self willChangeValueForKey:@"openingBalance"];
        _openingBalance = theBalance;
        [self didChangeValueForKey:@"openingBalance"];
    }
}

Если единственная работа заставляет многократные ключи изменяться, необходимо вложить уведомления изменения как показано в Перечислении 5.

  Вложение перечисления 5 изменяет уведомления для многократных ключей

- (void)setOpeningBalance:(double)theBalance {
    [self willChangeValueForKey:@"openingBalance"];
    [self willChangeValueForKey:@"itemChanged"];
    _openingBalance = theBalance;
    _itemChanged = _itemChanged+1;
    [self didChangeValueForKey:@"itemChanged"];
    [self didChangeValueForKey:@"openingBalance"];
}

В случае упорядоченного - многие отношение, необходимо указать не только ключ, изменившийся, но также и тип изменения и индексы включенных объектов. Тип изменения NSKeyValueChange это указывает NSKeyValueChangeInsertion, NSKeyValueChangeRemoval, или NSKeyValueChangeReplacement. Индексы задействованных объектов передаются как NSIndexSet объект.

Фрагмент кода в Перечислении 6 демонстрирует, как обернуть удаление объектов в к - многие отношение transactions.

  Реализация перечисления 6 ручного уведомления наблюдателя в к - многие отношение

- (void)removeTransactionsAtIndexes:(NSIndexSet *)indexes {
    [self willChange:NSKeyValueChangeRemoval
        valuesAtIndexes:indexes forKey:@"transactions"];
 
    // Remove the transaction objects at the specified indexes.
 
    [self didChange:NSKeyValueChangeRemoval
        valuesAtIndexes:indexes forKey:@"transactions"];
}