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

Когда использовать "willChangeValueForKey" и "didChangeValueForKey"?

Я видел эти строки в демонстрационном проекте, но я не мог понять, почему он это сделал.

[self willChangeValueForKey:@"names"];
[self didChangeValueForKey:@"names"];

Он вызвал didChangeValueForKey сразу после willChangeeValueForKey. Имеет ли смысл?

Кроме того, когда должно быть подходящее время для вызова этих двух методов? Большое спасибо!!:)

4b9b3361

Ответ 1

Это, по сути, анти-шаблон. Вы не должны называть -willChangeValueForKey:, а затем -didChangeValueForKey: без какого-либо промежуточного изменения фактического свойства. В некоторых случаях это может маскировать проблемы KVO в другом месте вашего кода и заставлять наблюдателей обновлять свое состояние, связанное с соответствующим имуществом. В конечном счете, однако, вы (или автор примера, который вы цитируете) должны исправить остальную часть кода, чтобы этот анти-шаблон не был необходим.

Правильное использование -will|didChangeValueForKey: - это когда вы изменяете свойство без использования совместимых с KVC аксессуаров/сеттеров, чтобы механизм KVO не заметил изменения. Для надуманного примера рассмотрите возможность изменения переменной экземпляра базы данных для атрибута напрямую:

@interface Foo
{
   int bar;
}
@end

@implementation Foo
- (void)someMethod
{
  bar = 10;
}
@end

Наблюдатели KVO, зарегистрированные для уведомления об изменениях в свойстве bar, не получили уведомление об изменении на bar в -someMethod. Чтобы сделать работу машины KVO, вы можете изменить -someMethod:

- (void)someMethod
{
  [self willChangeValueForKey:@"bar"];
  bar = 10;
  [self didChangeValueForKey:@"bar"];
}

Конечно, было бы лучше использовать объявление @property и использовать KVC-совместимые аксессоры/сеттеры (либо вручную, либо @synthesized), но это надуманный пример.

Ответ 2

KVO будет корректно работать с настраиваемыми сеттерами для свойств; это всегда имело место для классов, основанных на NSObject. Механизм времени выполнения ищет вызов соответствующего метода setter и неявно вызывает "willChangeValueForKey" до запуска setter, а затем неявно вызывает "didChangeValueForKey" после завершения установки.

Вы можете отключить это автоматическое поведение, если хотите иметь более мелкомасштабный контроль над уведомлениями KVO. Как упоминалось выше, свойства readonly, значение которых вы изменяете, изменяя базовый ivar или значения которого выведены вычислением, являются местами, где вы будете использовать ручные уведомления (хотя есть механизм keyPathsAffectingValueFor, где вы можете указать время выполнения, значение свойства зависит от изменения другого свойства, и оно отправит уведомление об изменении, если это необходимо.) Чтобы отключить автоматическое поведение для каждого свойства, вы помещаете метод класса + (BOOL) автоматическиNotifiesObserversOf и возвращаете NO.

Я часто отключаю автоматические уведомления KVO, потому что обнаружил, что при вызове установщика генерируется уведомление KVO, даже если значение свойства устанавливается равным его текущему значению (например, без изменений). Я хочу подавить бессмысленное уведомление ради эффективности:

+ (BOOL)automaticallyNotifiesObserversOfMyProperty
{
  return NO;
}

- (void)setMyProperty:(NSInteger)myProperty
{
  if(_myProperty != myProperty)
  {
    [self willChangeValueForKey:@"myProperty"];
    _myProperty = myProperty;
    [self didChangeValueForKey:@"myProperty"];
  }
}

Хорошее обсуждение можно найти в заголовке NSKeyValueObserving.h, к которому вы можете перейти с помощью CMD +, нажимая на имена методов "willChangeValueForKey" и "didChangeValueForKey" в XCode.

Ответ 3

Это связано с ручным контролем наблюдения за ключевыми значениями. Обычно система заботится об этом, но это позволяет вам контролировать. Посмотрите на эту документацию, чтобы понять, когда и как их использовать здесь.

Ответ 4

Согласитесь с Барри. Я просто встречаю ту же проблему. Вот пример использования этих двух методов. Я объявил свойство readonly. Поэтому я не могу использовать свойство accessor для изменения значения.

@property (nonatomic, readonly) BOOL var;

Когда я хочу изменить "var", мне нужно вызвать эти два метода вручную. В противном случае наблюдатели не получат уведомления.

self willChangeValueForKey:@"var"];
var = YES;
[self didChangeValueForKey:@"var"];

Ответ 5

  • Если вы хотите сделать материал непосредственно перед изменением значения, используйте параметр willChangeValueForKey.
  • Если вы хотите сделать материал сразу после изменения значения, используйте hasChangeValueForKey.

Изменить: игнорировать меня, читал слишком быстро - Барри прав: -)

Ответ 6

Будьте осторожны при переопределении didChangeValueForKey:. Лучше всего не делать этого вообще. Но если вы это сделаете, убедитесь, что вы вызываете super, иначе у вас будет утечка памяти, как показано здесь: https://github.com/jfahrenkrug/KVOMemoryLeak

Ответ 7

Проводка этого в июле 2013 года, и, похоже, уже нет необходимости вызывать will/didChangeValueForKey. Кажется, что позаботится об этом автоматически, даже если у вас есть пользовательский сеттер.