观察 UITableViewController 的编辑属性
为什么我无法观察 UITableViewController
实例的 editing
属性?
我正在使用以下代码:
[self addObserver:self
forKeyPath:@"editing"
options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
context:NULL];
并已实现该方法:
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
... 但是当该值更改时,永远不会调用 observeValueForKeyPath
方法。
根据 Apple 的确保 KVC 合规性部分:
对于属性或一对一关系的属性,这要求您的类:
- 实现名为
-
、-is
的方法,或具有实例变量或
_
。- 如果属性是可变的,那么它还应该实现
-set
。: - 您的
-set
方法的实现不应执行验证。: - 如果验证适合该密钥,您的类应该实现
-validate
。:error:
editing
属性的文档指出,它的定义如下:
@property(nonatomic, getter=isEditing) BOOL editing
由于该属性不可变,因此它必须符合的唯一要点是第一个(即有一个 -例如,定义了
方法)。通过查看属性的声明,您可以看到它确实符合这一点,并注意到定义了一个 isEditing
方法。因此,它应该符合键值观察。怎么不起作用呢?
Why can't I observe the editing
property of an instance of UITableViewController
?
I'm using the following code:
[self addObserver:self
forKeyPath:@"editing"
options:(NSKeyValueObservingOptionNew | NSKeyValueObservingOptionOld)
context:NULL];
And have implemented the method:
- (void)observeValueForKeyPath:(NSString *)keyPath
ofObject:(id)object
change:(NSDictionary *)change
context:(void *)context
... but the observeValueForKeyPath
method is never called when this value changes.
According to Apple's Ensuring KVC Compliance section:
For properties that are an attribute or a to-one relationship, this requires that your class:
- Implement a method named
-<key>
,-is<Key>
, or have an instance variable<key>
or_<key>
.- If the property is mutable, then it should also implement
-set<Key>:
.- Your implementation of the
-set<Key>:
method should not perform validation.- Your class should implement
-validate<Key>:error:
if validation is appropriate for the key.
The documentation for the editing
property, states that it is defined as:
@property(nonatomic, getter=isEditing) BOOL editing
Since this property is not mutable, the only bullet point it must conform to is the first one (i.e. that there is an -is<Key>
method defined, for example). You can see that it does conform to this by looking at the declaration of the property, and noticing that there is an isEditing
method defined. Thus, it should be Key Value Observing compliant. How come it isn't working?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(2)
您混淆了键值编码合规性和键值观察合规性。该属性符合 KVC 标准,这意味着您可以使用
[myViewController valueForKey:@"editing"]
来访问它(如果您喜欢打字),但这并不意味着它符合 KVO 标准。KVO-合规性是通过以下方式实现的 对象要么实现 KVC 兼容的 setter(要点 2 和 3),KVO 将自动包装该 setter,要么通过发送自身来手动发布 KVO 通知
will
/didChangeValueForKey:
消息。UIViewController 和 UITableViewController 没有公开实现
setEditing:
;如果他们根本不实现它,那么 KVO 自动包装它就已经过时了。这就留下了手动通知。如果您没有收到该属性的任何 KVO 通知(并且您实际上点击了addObserver:forKeyPath:options:context:
消息),则表明这些类都没有私下实现setEditing:
也不手动发布 KVO 通知。因此,该属性是不可观察的。
如果设置
editing
属性的唯一方法是向控制器发送setEditing:animated:
消息,那么您可以覆盖setEditing:animated:
> 并从您的实现中自行发送 KVO 通知,然后该属性将是可观察的。You're confusing Key-Value Coding compliance with Key-Value Observing compliance. The property is KVC-compliant, which means you can use
[myViewController valueForKey:@"editing"]
to access it (if you like typing), but this does not mean it is KVO-compliant.KVO-compliance is achieved by the object either implementing a KVC-compliant setter (bullet points 2 and 3), which KVO will wrap automatically, or manually posting KVO notifications by sending itself
will
/didChangeValueForKey:
messages.UIViewController and UITableViewController do not publicly implement
setEditing:
; if they don't implement it at all, then KVO wrapping it automatically is out. That leaves manual notifications. If you're not getting any KVO notifications for the property (and you are actually hitting thataddObserver:forKeyPath:options:context:
message), that suggests that those classes neither privately implementsetEditing:
nor manually post KVO notifications.Therefore, the property is not observable.
If the only way anything ever sets the
editing
property is by sending the controller asetEditing:animated:
message, then you can overridesetEditing:animated:
and send the KVO notifications yourself from your implementation, and then the property will be observable.这有点卡顿,但您可以通过观察
editButtonItem
的title
来解决这个问题。[self.viewControllerToObserve addObserver:self forKeyPath:@"editButtonItem.title" options:0 context:kMyViewControllerKVOContext];
仅供参考,这是我声明上下文的方式(在
@implementation
上方) :static void * const kMyViewControllerKVOContext = (void *)&kMyViewControllerKVOContext;
使用 Hopper ,我们可以看到在
UIViewController
的setEditing
期间,它创建了一个新的editButtonItem
,其标题取决于要更改的编辑内容。对于那些有兴趣的人来说,还有更多:
It's a bit janky but you can work around this by observing the
editButtonItem
'stitle
.[self.viewControllerToObserve addObserver:self forKeyPath:@"editButtonItem.title" options:0 context:kMyViewControllerKVOContext];
FYI this is how I declare my context (above
@implementation
):static void * const kMyViewControllerKVOContext = (void *)&kMyViewControllerKVOContext;
Using Hopper, we can see during
UIViewController
'ssetEditing
it creates a neweditButtonItem
with a title dependent on what editing is being changed to.Little more for those interested: