我在演示项目中看到了这些行,但我无法理解为什么会这样做。
[self willChangeValueForKey:@"names"];
[self didChangeValueForKey:@"names"];
在willChangeeValueForKey之后立即调用didChangeValueForKey。 它有意义吗?
此外,什么时候应该适时调用这两种方法? 非常感谢!! :)
答案 0 :(得分:49)
-willChangeValueForKey:
之后调用-didChangeValueForKey:
,而不会在没有任何实际属性更改的情况下调用-will|didChangeValueForKey:
。在某些情况下,这样做可能会掩盖代码中其他地方的KVO问题,并迫使观察者更新与相关属性相关的状态。但是,最终,您(或您引用的示例的作者)应该修复其余的代码,以便不需要这种反模式。
@interface Foo
{
int bar;
}
@end
@implementation Foo
- (void)someMethod
{
bar = 10;
}
@end
的正确用法是在不使用符合KVC的访问者/设置者修改属性时,KVO机制不会注意到更改。对于一个人为的例子,考虑直接修改属性的后备实例变量:
bar
已注册bar
属性变更通知的KVO观察员不会在-someMethod
中收到-someMethod
更改通知。要使KVO机器正常工作,您可以修改- (void)someMethod
{
[self willChangeValueForKey:@"bar"];
bar = 10;
[self didChangeValueForKey:@"bar"];
}
:
@property
当然,最好使用@synthesized
声明并使用符合KVC标准的访问者/设置者(手动编码或{{1}}),但这是一个人为的例子。
答案 1 :(得分: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"];
}
}
可以在NSKeyValueObserving.h标题中找到一个很好的讨论,你可以通过CMD +导航到XCode中的方法名称“willChangeValueForKey”和“didChangeValueForKey”。
答案 2 :(得分:1)
那些与手动控制键值观察有关。通常情况下,系统负责处理,但这些可以让您进行一些控制。请查看此文档以了解何时以及如何使用它们here。
答案 3 :(得分:1)
同意Barry。我只是遇到同样的问题。这是使用这两种方法的情况。 我宣布了一个只读属性。所以我不能使用属性的访问器来更改值。
@property (nonatomic, readonly) BOOL var;
当我想要更改“var”时,我需要手动调用这两个方法。否则,观察员将不会收到通知。
self willChangeValueForKey:@"var"];
var = YES;
[self didChangeValueForKey:@"var"];
答案 4 :(得分:0)
编辑:不理我,读得太快 - 巴里是对的: - )
答案 5 :(得分:0)
覆盖didChangeValueForKey:
时要非常小心。最好的事情就是不要这样做。但是,如果你这样做,请确保拨打super
,否则您将遇到内存泄漏,如下所示:https://github.com/jfahrenkrug/KVOMemoryLeak
答案 6 :(得分:0)
如果您重写属性获取器方法,请使用它。
@property (assign, nonatomic, getter=isLogined) BOOL logined;
答案 7 :(得分:-2)
在2013年7月发布,似乎不再需要调用will / didChangeValueForKey。即使您有自定义设置器,它似乎也会自动处理。