37

我已经在为我自己的 NSView 子类实现绑定方面有所突破。它可以工作,但是从 nib 文件绑定到文件所有者时,保留周期会出现问题。在读了一点之后,我发现苹果几年前也有同样的问题,但是用一些神奇的无证类(NSAutounbinder)修复了它。

这里有一个关于保留周期问题的冗长讨论http://www.cocoabuilder.com/archive/message/cocoa/2004/6/12/109600解决方法是在窗口控制器释放之前解除所有绑定,而不是在释放之前,在 windowWillClose: 之类的地方。这对我来说似乎是不必要的黑客攻击。

我的问题是:有什么方法可以使自定义绑定与 Apple 制作的绑定一样有效,而无需使用未记录的功能?我会以错误的方式解决这个问题吗?


更新 2:我找到了一个解决方案,它允许手动实现的绑定完全像 Apple 的绑定一样工作。它利用了未记录的 NSAutounbinder 类,而没有实际使用未记录的功能。我将在今天晚些时候发布解决方案。


更新:我试过使用exposeBinding:,它似乎没有任何区别。但是,NSObject执行bind:toObject:withKeyPath:options:一半有效。它传播从绑定者到绑定者的更改(即从模型/控制器到视图),但不能以相反的方式工作。此外,虽然 bindee 显然正在被观察,但从observeValueForKeyPath:ofObject:change:context:未被触发。

此处的示例项目:http ://www.tomdalling.com/wp-content/BindingsTest.zip

Apple 的文档表明,事实上,您必须重写bind:toObject:withKeyPath:options:才能实现手动绑定。见这里:http: //developer.apple.com/documentation/Cocoa/Conceptual/CocoaBindings/Concepts/HowDoBindingsWork.html


旁注:我已经调查了未记录的 NSAutounbinder 是如何工作的,这就是我所知道的。

当为 NSWindowController 创建绑定时,绑定的对象实际上是一个 NSAutounbinder,它通过 -[NSWindowController _autounbinder] 从 NSWindowController 获取。NSAutounbinder 是 NSWindowController 对象的非保留代理。避免保留循环问题是非保留的。

当 -[NSWindowController release] 被调用并且 retainCount == 1 时,NSAutounbinder 将所有绑定解除绑定到自身。这确保了在对象被释放之前没有悬空指针。

4

4 回答 4

22

这是我能找到的最佳解决方案。我在这里有更详细的讨论和演示代码:http: //tomdalling.com/blog/cocoa/implementing-your-own-cocoa-bindings/

基本上,您不会覆盖bind:toObject:withKeyPath:options:or unbind:NSObject将使用默认实现NSAutounbinder来避免保留循环。正如 Louis Gerbarg 指出的那样,仍然存在NSAutounbinder无法发挥作用的情况。但是,您可以使绑定至少与 Apple 的绑定一样工作。

由于视图更改时的默认实现bind:toObject:withKeyPath:options:不会更新模型,因此必须手动传播视图驱动的更改。您可以使用-[NSObject infoForBinding:]来获取更新绑定对象所需的所有信息。我在 NSObject 上添加了自己的方法,其中包含一个类别:

-(void)propagateValue:(id)value forBinding:(NSString*)binding;

它处理获取绑定对象、绑定键路径和应用值转换器。该实现可从顶部的链接获得。

于 2009-07-31T03:40:27.980 回答
3

简短的回答是,不,在调用代码和 nib 中没有解决方法的情况下,你无法让它工作。甚至 NSAutounbinder 也遗漏了 NSDocument 和 NSWindowController 的一些案例,如果 Apple 无法使其在 2 个类中正常工作,那么他们专门为我们这些无法访问 AppKit 内部的人配备了基本没有机会。

话虽如此,有两种解决方法可能比在 windowWillClose: 中解除绑定要好一些。

  1. 不要绑定到文件的所有者,而是将 NSObjectController 作为根级别对象拖到 nib 中并绑定到它,然后在 awakeFromNib 期间在对象控制器上设置内容:
  2. 打开垃圾收集。如果这是一个选项,它可以解决所有对象循环问题;-) 显然 GC 引入了它自己的问题,如果你需要 10.4 兼容性,它是一个非首发。
于 2009-07-26T15:36:05.307 回答
3

请参阅 mmalc 的GraphicsBindings示例,了解如何实现您自己的绑定的一个很好的示例。您需要实现NSKeyValueBindingCreation非正式协议才能使其正常工作。为了让你的控制器知道有些东西可以绑定,在你的视图的 + (id)initialize 方法中调用exposeBinding:

+ (void)initialize { [self exposeBinding:@"ILIKEBINDAGE"]; }

然后,您需要在 NSKeyValueBindingCreation 协议中实现每个绑定管理方法。您基本上需要为视图设置 KVO,以便它知道何时根据应用程序的行为进行更新并处理清理(取消绑定:)。

这是很多额外的、相当丑陋的代码,因此使用传统的胶水代码可能效果更好并且更易于阅读。

于 2009-07-27T07:01:02.410 回答
2

您可能想查看NSKeyValueBindingCreation Protocol。它允许您通过代码以编程方式创建绑定。(如果您需要引用 IBOutlet 变量,请记住在 awakeFromNib 方法中完成这项工作,否则它们可能为零。)

于 2009-07-23T05:26:55.107 回答