【问题标题】:Implement own setter or use KVO?实现自己的setter还是使用KVO?
【发布时间】:2011-05-05 06:14:35
【问题描述】:

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

- (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 指令,我选择相信编译器比我的 owe setter 实现更聪明,因此我不会破坏某些东西.

【问题讨论】:

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


    【解决方案1】:

    如果您对同一对象的更改感兴趣,第一个 sn-p 是要走的路。如果你对其他对象的更改感兴趣,只需要使用第二个,用它来观察self 是大材小用。

    【讨论】:

    • 怎么会矫枉过正?假设您想观察自己的计算属性,该属性取决于其他 5 个属性。您真的不想为此编写 5 个 getter 吗?
    • 一如既往,您只能说视情况而定。对于这个问题中描述的简单情况,设置 KVO 是多余的。对于像您描述的更复杂的用例,KVO 可能是合理的。
    • 这可能确实有点开销,但我更喜欢保持我的代码正确分组,而不是让观察逻辑分布在 20 个方法上。 Objective-C 不是——从来不是——关于性能。我真的认为这种开销是值得的,因为它的清晰度、一致性和扩展能力非常好。
    【解决方案2】:

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

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

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

    有时您可以使用绑定(如果您在 Mac 上)或普通通知(您可以发布模型更改并且所有相关方都应该刷新的通知)等其他方法来回避问题。

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

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

    这需要更多的工作,但它会保持你的类干净地分开,你可以在一个地方解决所有与 KVO 相关的问题。如果没有足够的重新计算属性来使这个有价值,我通常会使用第一个解决方案(自定义设置器)。

    【讨论】:

    • 当你有一个属性并且你正在覆盖/实现setter时,你don't need to call willChangeValyeForKey: and didChangeValueForKey:,编译器已经为你做了。
    • 对,你通常不需要打电话给will/didChangeValueForKey:。但让这一切发生的不是编译器——而是运行时。如果您自己在一个简单的 setter 中调用它,这些方法将被调用两次,除非您还实现类方法 automaticallyNotifiesObserversForKey: 以返回给定属性的 NO
    • 啊!是的,对不起,你是对的。我忘了通知不是由类中的访问器发送的,而是由 swizzled 方法发送的。
    【解决方案3】:

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

    ,则您的 setter 实现是正确的

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

    KVO 通常用于检查外部对象属性的变化。

    NSNotifications 更适合通知事件。

    【讨论】:

      猜你喜欢
      • 2018-01-31
      • 1970-01-01
      • 2012-12-20
      • 1970-01-01
      • 2015-10-05
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-02-05
      相关资源
      最近更新 更多