何时使用"willChangeValueForKey"和"didChangeValueForKey"?

Fro*_*ost 29 macos objective-c

我在演示项目中看到了这些行,但我无法理解为什么会这样做.

[self willChangeValueForKey:@"names"];
[self didChangeValueForKey:@"names"];
Run Code Online (Sandbox Code Playgroud)

它在willChangeeValueForKey之后立即调用didChangeValueForKey.它有意义吗?

此外,什么时候应该适时调用这两种方法?非常感谢!!:)

Bar*_*ark 49

事实上,这是一种反模式.如果没有任何干预实际的财产变更,你不应该打电话-willChangeValueForKey:跟随-didChangeValueForKey:.在某些情况下,这样做可能会掩盖代码中其他地方的KVO问题,并迫使观察者更新与相关属性相关的状态.但是,最终,您(或您引用的示例的作者)应该修复其余的代码,以便不需要这种反模式.

正确使用的-will|didChangeValueForKey:是当您在不使用符合KVC的访问者/设置者的情况下修改属性时,KVO机制不会注意到更改.对于一个人为的例子,考虑直接修改属性的后备实例变量:

@interface Foo
{
   int bar;
}
@end

@implementation Foo
- (void)someMethod
{
  bar = 10;
}
@end
Run Code Online (Sandbox Code Playgroud)

了登记在更改通知志愿观察员bar财产不会收到变更通知到bar-someMethod.要使KVO机器工作,您可以修改-someMethod:

- (void)someMethod
{
  [self willChangeValueForKey:@"bar"];
  bar = 10;
  [self didChangeValueForKey:@"bar"];
}
Run Code Online (Sandbox Code Playgroud)

当然,最好使用@property声明并使用符合KVC标准的访问者/设置者(手动编码或@synthesized),但这是一个人为的例子.


小智 11

KVO将使用定制的属性设置器正确运行; 这一直是NSObject派生类的情况.运行时机制查找相关setter方法的调用,并在执行setter之前隐式调用"willChangeValueForKey",然后在setter完成后隐式调用"didChangeValueForKey".

如果您希望对KVO通知进行更细粒度的控制,则可以禁用此自动行为.如上所述,readonly属性通过修改支持ivar或通过计算得出其值来更改的值是您将使用手动通知的位置(尽管有一个机制,keyPathsAffectingValueFor,您可以在其中告诉运行时属性的值取决于另一个属性的更改,并且它将根据需要发送更改通知.)要在每个属性的基础上禁用自动行为,您将自定义类方法+(BOOL)自动注释ObserversOf并返回NO .

我经常禁用自动KVO通知,因为我发现在调用setter时会生成KVO通知,即使该属性的值设置为与其当前值相同(例如,没有更改).为了效率,我希望压制无意义的通知:

+ (BOOL)automaticallyNotifiesObserversOfMyProperty
{
  return NO;
}

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

可以在NSKeyValueObserving.h标头中找到一个很好的讨论,你可以通过CMD +导航到XCode中的方法名称"willChangeValueForKey"和"didChangeValueForKey".