你可以手动实现cocoa绑定?

我已经在我自己的NSView子类实现绑定了一个裂缝。 它可以工作,但从nib文件绑定到文件所有者时,保留周期存在问题。 稍微阅读一下后,我发现苹果几年前也有同样的问题,但是已经用一些无证的类(NSAutounbinder)修复了它。

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

我的问题是这样的:有没有办法使自定义绑定,以及由苹果公司的作品,而不使用无证的function? 我是否以错误的方式去做这件事?


更新2:我发现了一个解决scheme,允许手动实现的绑定工作完全像苹果的绑定。 它利用未logging的NSAutounbinder类,没有实际使用未logging的特征。 我将在今天晚些时候发布解决scheme。


更新: 我试着使用exposeBinding:它似乎没有任何区别 。 然而, NSObjectbind:toObject:withKeyPath:options:一半的工作。 它传播从绑定到绑定(即从模型/控制器到查看)的变化,但不会以相反的方式工作。 而且,虽然绑定器显然被观察到, observeValueForKeyPath:ofObject:change:context:从不被触发。

示例项目在这里: http : //www.tomdalling.com/wp-content/BindingsTest.zip

苹果的文档表明你实际上必须重写bind:toObject:withKeyPath:options:来实现手动绑定。 看到这里: http : //developer.apple.com/documentation/Cocoa/Conceptual/CocoaBindings/Concepts/HowDoBindingsWork.html


侧注:我已经调查了无证的NSAutounbinder是如何工作的,这里是我所知道的。

绑定创build到NSWindowController时,绑定对象实际上是一个NSAutounbinder,从NSWindowController通过 – [NSWindowController _autounbinder]获取。 NSAutounbinder是NSWindowController对象的非保留代理。 避免保留周期问题是没有保留的。

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

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

基本上,你不要重写bind:toObject:withKeyPath:options:unbind: bind:toObject:withKeyPath:options: NSObject的默认实现将使用NSAutounbinder来避免保留周期。 正如Louis Gerbarg所指出的那样, NSAutounbinder仍然存在的情况仍然存在。但是,您可以使绑定至less和Apple的绑定一样工作。

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

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

它处理获取绑定对象,绑定关键path和应用值转换器。 实现可以从顶部的链接获得。

简短的回答是,不,你不能在调用代码和nib中没有解决方法。 即使NSAutounbinder错过了NSDocument和NSWindowController的一些情况下,如果苹果不能正确地为2个class级正常工作,他们专门build立我们这些没有访问内部AppKit的基本上没有机会。

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

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

你可能想要签出NSKeyValueBindingCreation协议 。 它允许您通过代码以编程方式创build绑定。 (如果需要引用IBOutletvariables,请记住在awakeFromNib方法中执行此操作,否则它们可能为零)。

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

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

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

这是很多额外的,相当丑陋的代码,所以它可能是使用传统胶水代码更好,更容易阅读。