Соответствие KVO
Для рассмотрения KVO-совместимым для определенного свойства, класс должен гарантировать следующее:
Класс должен быть значением ключа, кодирующим совместимый для свойства, как указано в Обеспечении Соответствия KVC.
KVO поддерживает те же типы данных как KVC.
Класс испускает уведомления изменения 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"]; |
} |