37

自分のNSViewサブクラスのバインディングを実装するのに問題がありました。動作しますが、nibファイルからファイルの所有者にバインドするときの保持サイクルに問題があります。少し読んだ後、私はAppleが数年前に同じ問題を抱えていることを発見しましたが、いくつかの魔法の文書化されていないクラス(NSAutounbinder)でそれを修正しました。

ここhttp://www.cocoabuilder.com/archive/message/cocoa/2004/6/12/109600で、保持サイクルの問題について長い議論があります。回避策は、windowWillClose:のような場所で、ウィンドウコントローラが解放される前に、割り当てが解除される前ではなく、すべてのバインディングのバインドを解除することです。これは私には不必要なハックのようです。

私の質問はこれです:文書化されていない機能を使用せずに、Appleによって作成されたものと同様に機能するカスタムバインディングを作成する方法はありますか?私はこれを間違った方法で行っていますか?


更新2:手動で実装されたバインディングがAppleのバインディングとまったく同じように機能することを可能にするソリューションを見つけました。文書化されていない機能を実際に使用することなく、文書化されていないNSAutounbinderクラスを利用します。解決策は本日遅くに投稿します。


更新:を使用してみましexposeBinding:たが、違いはないようです。ただし、半分のNSObject実装は機能します。bind:toObject:withKeyPath:options:バインド先からバインダーへ(つまり、モデル/コントローラーからビューへ)変更を伝播しますが、逆の方法では機能しません。また、バインド先は明らかに監視されていますが、トリガーされる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へのバインディングが作成されると、バインドされたオブジェクトは実際には、-[NSWindowController_autounbinder]を使用してNSWindowControllerから取得されるNSAutounbinderです。NSAutounbinderは、NSWindowControllerオブジェクトの非保持プロキシです。保持サイクルの問題を回避することは非保持です。

-[NSWindowControllerrelease]が呼び出されてretainCount==1の場合、NSAutounbinderはすべてのバインディングをそれ自体にバインド解除します。これにより、割り当てが解除される前に、オブジェクトへのダングリングポインタがなくなります。

4

4 に答える 4

22

これが私が見つけることができる最良の解決策です。詳細な議論とデモ コードはこちらにあります: http://tomdalling.com/blog/cocoa/implementing-your-own-cocoa-bindings/

基本的に、orをオーバーライドしないでください。のデフォルトの実装では、保持サイクルを回避するために使用されます。Louis Gerbarg が指摘したように、まだ有効にならない状況があります。ただし、少なくとも Apple のバインディングと同様に、独自のバインディングを機能させることはできます。bind:toObject:withKeyPath:options:unbind:NSObjectNSAutounbinderNSAutounbinder

の既定の実装でbind:toObject:withKeyPath:options:は、ビューが変更されたときにモデルが更新されないため、ビュー駆動の変更は手動で伝達する必要があります。-[NSObject infoForBinding:]バインドされたオブジェクトを更新するために必要なすべての情報を取得するために使用できます。カテゴリを使用して NSObject に独自のメソッドを追加しました。

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

バインドされたオブジェクト、バインドされたキー パスの取得、および値トランスフォーマーの適用を処理します。実装は上部のリンクから入手できます。

于 2009-07-31T03:40:27.980 に答える
3

独自のバインディングを実装する方法の良い例については、mmalcのGraphicsBindingsの例を参照してください。それを機能させるには、 NSKeyValueBindingCreation非公式プロトコルを実装する必要があります。バインドできるものがあることをコントローラーに通知するには、ビューの+(id)initializeメソッドでexposeBindingを呼び出します。

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

次に、NSKeyValueBindingCreationプロトコルのメソッドを管理する各バインディングを実装する必要があります。基本的に、ビューのKVOをセットアップして、アプリケーションの動作に基づいて更新するタイミングを認識し、クリーンアップを処理する必要があります(unbind:)。

余分な、かなり醜いコードがたくさんあるので、従来のグルーコードを使用するとうまく機能し、読みやすくなる可能性があります。

于 2009-07-27T07:01:02.410 に答える
3

簡単に言えば、いいえ、呼び出し元のコードと nib に回避策がないと、動作させることはできません。NSAutounbinder でさえ、NSDocument と NSWindowController のいくつかのケースを見逃しています。Apple が 2 つのクラスで正しく動作しない場合、AppKit の内部にアクセスできない私たちを特別に装備する可能性は基本的にありません。

そうは言っても、windowWillClose: でバインドを解除するよりも少し良い回避策が 2 つあります。

  1. File's Owner にバインドしないで、代わりに NSObjectController をルート レベル オブジェクトとして nib にドラッグしてバインドし、awakeFromNib 中にオブジェクト コントローラーで setContents: を実行します。
  2. ガベージ コレクションをオンにします。それがオプションである場合、すべてのオブジェクトサイクルの問題が解決されます;-) 明らかに GC は独自の問題を引き起こします。
于 2009-07-26T15:36:05.307 に答える
2

NSKeyValueBindingCreation Protocolを確認してください。コードを使用してプログラムでバインディングを作成できます。(IBOutlet 変数を参照する必要がある場合、または変数が nil である可能性がある場合は、awakeFromNib メソッドで作業を行うことを忘れないでください。)

于 2009-07-23T05:26:55.107 に答える