实施自己的setter或使用KVO?

时间:2011-05-05 06:14:36

标签: objective-c properties key-value-observing setter

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

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

或:

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

哪种方法最好,为什么?

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

3 个答案:

答案 0 :(得分:5)

如果您对同一对象的更改感兴趣,那么第一个片段就是您的选择。如果您对其他对象的更改感兴趣,则只需使用第二个,使用它来观察self是否过度。

答案 1 :(得分:3)

艰难的电话,恕我直言两种选择都很糟糕。

第一个强迫你编写自己的setter,这是很多样板代码。 (更不用说如果你想让相关财产的KVO工作,你必须记得用willChangeValueForKey:didChangeValueForKey:发送KVO通知。)

第二个选项也很重,你的实现还不够。如果您的超类也有一些KVO怎么办?你必须在处理程序的某个地方调用super。如果没有,你确定你的超类不会改变吗? (更多关于related question中的KVO。)

有时你可以使用其他方法来回避问题,比如绑定(如果你在Mac上)或普通通知(你可以发布模型改变的通知,所有感兴趣的人都应该刷新)。

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

[self addTriggerForKeyPath:@"foo" action:^{
    NSLog(@"Foo changed.");
}];

这将需要更多工作,但它会使您的课程保持清晰分离,您可以在一个地方解决所有与KVO相关的问题。如果没有足够的重新计算属性来实现这个价值,我通常会选择第一个解决方案(自定义设置器)。

答案 2 :(得分:0)

在您的情况下,最好的选择是在setter中添加逻辑。如果您的属性声明类似于

,那么您的setter实现是正确的

@property(非原子,复制)YCYourClass * prop;

在检查外部对象属性的更改时,通常会使用KVO。

NSNotifications更适合告知事件。