【问题标题】:KVO notifications with a custom property getter带有自定义属性 getter 的 KVO 通知
【发布时间】:2013-11-16 01:16:17
【问题描述】:

我正在尝试在 iOS 中收听 UITextView 上的 editable 属性。在UITextView.h 的标头中,editable 属性定义为:

@property(nonatomic,getter=isEditable) BOOL editable;

为了监听 KVO 通知,我使用了 addObserver 模式,其中我将 keyPath 作为NSStringFromSelector(@selector(isEditable)) 传递,因此如果我使用未定义的选择器,Xcode 会警告我。注册isEditable 键路径顺利进行,但是在更改文本视图上的editable 属性后,我从未收到属性更改的通知。我正在注册观察者:

[self.textView addObserver:self
                forKeyPath:NSStringFromSelector(@selector(isEditable))
                   options:NSKeyValueObservingOptionNew
                   context:KVOTestingTestsContext];

但是,如果我改为使用密钥路径 NSStringFromSelector(@selector(editable)),我确实会收到 KVO 通知,但 Xcode 会生成一条警告,指出我正在使用未声明的选择器“可编辑”。

我想知道是否有更好的模式,如果在应该使用自定义 getter 的情况下出现故障,我应该使用它。或者这是 Xcode / clang 中的错误?

【问题讨论】:

  • 我创建了一个示例项目here,其中有a testcase 显示此失败。

标签: ios objective-c key-value-observing


【解决方案1】:

您应该在addObserverforKeyPath 参数中传递属性的名称,而不是getter 或setter:

[self.textView addObserver:self
                forKeyPath:@"editable"
                   options:NSKeyValueObservingOptionNew
                   context:KVOTestingTestsContext];

无需使用NSStringFromSelector@selector 生成密钥路径。事实上,当你这样做时,你可能会遇到你所面临的问题......

  1. 键路径基于属性的名称,而不是 getter。这样做的原因是您希望 KVO 拦截 setEditable 方法。如果你将@"isEditable"(不管它是如何生成的)传递给addObserver,KVO 会尝试拦截一个名为isEditable 的属性的setter,而这个属性并不存在。

  2. 您使用第二种方法收到通知,因为您最终将 @"editable" 传递给 addObserver,这是您想要做的,但您是通过引用不存在的方法(即editable),因此是编译器警告。

  3. 由于您不能将 getter 或 setter 方法的名称传递给 addObserver,因此答案是直接使用字符串文字(即 @"editable")传递属性名称。

这是 Apple 的编程指南供参考:Registering for Key-Value Observing

【讨论】:

  • +1 尤其是“godel”的 +1。不确定这是否与您的名字有关,但 en.wikipedia.org/wiki/Gödel,_Escher,_Bach 启发了我学习 CS。
  • @danh 这正是它的来源,我同意学习 CS 的灵感! :-)
  • 使用NSStringFromSelector(@selector(...)) 被认为是一种好的做法的原因是您可以通过这种方式获得编译器检查密钥是否存在。这可以让您在意识到您的关键路径中有错字之前,不必担心为什么没有调用您的观察者。
  • 我花了一段时间才真正理解这个问题的原因。正如您所说,KVO 想要的 keypath 是 @property 名称,虽然这通常与属性的 getter 相同,但不一定如此。使用NSStringFromSelector(@selector(myProperty)) 是一个很好但有点老套的技巧。
  • 另外,大多数人可能从 NSHipster 的 KVO 页面获得 @selector 技巧,该页面使用自定义 getter 名称作为示例:NSStringFromSelector(@selector(isFinished))
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-09-09
  • 1970-01-01
  • 2014-12-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多