实施自己的setter或使用KVO?

cxa*_*cxa 12 setter properties objective-c key-value-observing

简而言之,当属性值发生变化时,我必须更新代码中的一些逻辑,例如:

- (void)setProp:(NSString *)theProp
{
  if (prop != theProp){
    [prop release];
    prop = [theProp copy];
    [self myLogic];
  }
}
Run Code Online (Sandbox Code Playgroud)

要么:

- (void)observeValueForKeyPath:(NSString *)keyPath
                      ofObject:(id)object
                        change:(NSDictionary *)change
                       context:(void *)context
{
  if ([keyPath isEqualToString:@"prop"]){
    [self myLogic];
  }  
}
Run Code Online (Sandbox Code Playgroud)

哪种方式最好,为什么?

编辑:我完全采用第二种方式,因为我不知道编译器会@synthesize为我生成指令,我选择相信编译器比我欠的setter实现更聪明,因此我不会破坏某些东西.

Sve*_*ven 5

如果您对同一对象的更改感兴趣,则可以使用第一个代码段.如果您对其他对象的更改感兴趣,则只需要使用秒,使用它来观察self是否过度.


zou*_*oul 3

艰难的决定,恕我直言,这两种选择都很糟糕。

\n\n

第一个强制您编写自己的 setter,这是一组\xc2\xa0lot 样板代码。(更不用说如果您希望相关属性的 KVO 正常工作,您还必须记住使用willChangeValueForKey:和来触发 KVO 通知。)didChangeValueForKey:

\n\n

第二个选项也相当重量级,您的实现还不够。如果你的超类也有一些 KVO 怎么办?您\xe2\x80\x99d 必须调用super处理程序中的某个位置。如果没有,您确定您的超类不会改变\xe2\x80\x99t吗?(有关 KVO 的更多信息,请参阅相关问题。)

\n\n

有时,您可以使用其他方法来回避问题,例如绑定(如果您\xe2\x80\x99 使用的是 Mac)或普通通知(您可以发布模型更改的通知,所有感兴趣的各方都应该刷新)。

\n\n

如果您有很多像这样的重新计算并且不能找到任何更好的方法,我会尝试编写一个具有更好观察支持的超类,其接口如下:

\n\n
[self addTriggerForKeyPath:@"foo" action:^{\n    NSLog(@"Foo changed.");\n}];\n
Run Code Online (Sandbox Code Playgroud)\n\n

这将需要更多的工作,但它会让你的类清晰地分开,并且你可以在一个地方解决所有与 KVO 相关的问题。如果没有足够的重新计算属性来使其有价值,则 I\xc2\xa0 通常采用第一个解决方案(自定义设置器)。

\n

  • 当您拥有一个属性并且要覆盖/实现设置器时,您[不需要调用`willChangeValyeForKey:`和`didChangeValueForKey:`](http://stackoverflow.com/questions/3261139/do-you-need -to-call-willchangevalueforkey-and-didchangevalueforkey),编译器已经为您完成了该操作。 (7认同)