【问题标题】:Why is this code not KVO-Compliant?为什么这段代码不符合 KVO 标准?
【发布时间】:2012-01-12 03:58:47
【问题描述】:

我有一个 NSViewController 子类,它有一个方便的方法来返回这样的窗口控制器

@interface ILViewController : NSViewController

- (ILWindowController *)windowController;

@end

@implementation ILViewController

- (NSWindowController *)windowController {
    return self.view.window.windowController;
}

- (void)setView:(NSView *)view {
    [self willChangeValueForKey:@"windowController"];
    [super setView:view];
    [self didChangeValueForKey:@"windowController"];
}

@end

窗口控制器有一个名为mainStatusNSString * 属性,我试图通过视图控制器绑定到该属性。但是,我在运行时收到此错误。

Cannot update for observer <NSAutounbinderObservance 0x1005cf990> for the key path 
"windowController.mainStatus" from <ILViewController 0x1001976b0>, most likely because
the value for the key "windowController" has changed without an appropriate KVO
notification being sent. Check the KVO-compliance of the ILViewController class.

为什么会这样?我已经适当地发送了 KVO 通知。

以下代码使用 ivar,实际上不符合 KVO,结果证明不会导致任何错误......

@interface ILViewController : NSViewController {
    ILWindowController *_windowController;
}

- (ILWindowController *)windowController;

@end

@implementation ILViewController

- (NSWindowController *)windowController {
    return _windowController;
}

- (void)setView:(NSView *)view {
    [super setView:view];
    _windowController = view.window.windowController;
}

@end

这让我很困惑......有人能明白为什么第一个实现不符合 KVO 吗?

编辑

知道了,如果在为 ViewController 设置视图之后将视图添加到窗口,那么视图的窗口确实会在没有适当 KVO 通知的情况下更改。但是,当我尝试观察视图的窗口的窗口控制器时,我遇到了这样的错误

KVO autonotifying only supports -set<Key>: methods that return void. Autonotifying 
will not be done for invocations of -[NSView _setWindow:].
Cannot remove an observer <NSKeyValueObservance 0x102e17880> for the key path
"window.windowController.mainStatus" from <NSView 0x102e13ec0>, most likely because
the value for the key "window" has changed without an appropriate KVO notification
 being sent. Check the KVO-compliance of the NSView class.

因此,如果您无法观察视图的窗口,那么当视图的窗口发生变化时,肯定有一些方法可以通知您。有人知道怎么做吗?

此外,这些仍然不能解释为什么使用没有 KVO 通知的 iVar 的代码的第二个版本实际上可以工作。

【问题讨论】:

  • 您不需要在符合 KVC 的设置器中发送 KVO 通知。 KVO 将包装任何此类设置器并为您发送通知,除非您明确告诉它不要这样做。
  • 我正在发送 KVO 通知以获取所设置的属性会影响的不同属性。
  • 您仍然不需要自己发送 KVO 通知。相反,实现keyPathsForValuesAffectingWindowController,并返回一个集合,其唯一的对象是@"view"
  • 是的,我也试过了。在这两种情况下,它仍然不能解决观察视图窗口的问题
  • 没有理由这样做。它的作用是让您不必自己实现-[ILViewController setView:]

标签: objective-c cocoa binding key-value-observing


【解决方案1】:

如果您设置视图,然后将视图添加到窗口,则windowController 将发生更改,而不会发送 KVO 通知。您需要观察您自己的视图的window 并在发生更改时发送 will/did 更改通知(自动键路径依赖项可能会为您执行此操作,我不记得它实际上是否适用于路径或仅适用于值) .同样,如果窗口的windowController 发生变化,您也会遇到同样的问题。

编辑:该方法称为-automaticallyNotifiesObserversForKey:。我倾向于说它不支持关键路径,所以你必须自己手动观察/通知。

【讨论】:

  • 谢谢,虽然观察视图的窗口实际上似乎不起作用,请参阅我在原始问题中的编辑。
  • 该方法实际调用的是+automaticallyNotifiesObserversForKey:
【解决方案2】:

KVO 自动通知仅支持 -set: 返回 void 的方法

某些方法未声明,您的编译器可能会认为它的返回 id 并继续。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2011-01-24
    • 1970-01-01
    • 1970-01-01
    • 2021-06-21
    • 2011-05-27
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多