когда использовать "willChangeValueForKey" и "didChangeValueForKey"? - PullRequest
29 голосов
/ 11 июня 2010

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

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

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

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

Ответы [ 8 ]

49 голосов
/ 11 июня 2010

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

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

@interface Foo
{
   int bar;
}
@end

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

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

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

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

11 голосов
/ 09 августа 2013

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

Вы можете отключить это автоматическое поведение, если выхотите иметь более детальный контроль над уведомлениями KVO.Как упомянуто выше, свойства только для чтения, значение которых вы изменяете путем изменения вспомогательного 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.

1 голос
/ 28 марта 2012

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

@property (nonatomic, readonly) BOOL var;

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

self willChangeValueForKey:@"var"];
var = YES;
[self didChangeValueForKey:@"var"];
1 голос
/ 11 июня 2010

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

0 голосов
/ 03 августа 2018

если вы переписываете методы получения свойств, используйте его.

@property (assign, nonatomic, getter=isLogined) BOOL logined;
0 голосов
/ 04 марта 2014

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

0 голосов
/ 01 августа 2013

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

0 голосов
/ 11 июня 2010
  • Если вы хотите сделать что-то незадолго до изменения значения, используйте willChangeValueForKey.
  • Если вы хотите сделать что-то сразу после изменения значения, используйте didChangeValueForKey.

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...