バインド可能にしたいプロパティを持つ NSView サブクラスがあります。サブクラスに以下を実装しました。
myView.h:
@property (readwrite, retain) NSArray *representedObjects;
myView.m:
@synthesize representedObjects;
+(void)initialize
{
[self exposeBinding: @"representedObjects"];
}
-(void)bind:(NSString *)binding toObject:(id)observableController withKeyPath:(NSString *)keyPath options:(NSDictionary *)options
{
if ([binding isEqualToString:@"representedObjects"]) {
[observableController addObserver: self forKeyPath:@"arrangedObjects" options:NSKeyValueChangeNewKey context:nil];
} else {
[super bind: binding toObject:observableController withKeyPath:keyPath options: options];
}
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context
{
if ([keyPath isEqualToString:@"arrangedObjects"]) {
[self setRepresentedObjects: [object arrangedObjects]];
}
}
次に、arrayController へのバインディングを次のように作成します-[AppController awakeFromNib]
。
[myView bind:@"representedObjects" toObject:arrayController withKeyPath:@"arrangedObjects" options: nil];
これはバインディングを実装する正しい方法ですか? それには多くの定型コードが含まれているため、何か間違ったことをしていると思います。
NSObject は手動で行ったことを自動的に実装すると思っていまし-bind:toObject:withKeyPath:options:
たが、そうではないようです。コメントアウトすると-bind:toObject:withKeyPath:options:
、setRepresentedObjects メソッドは呼び出されません。
追加情報:さらに調査を行った結果、元のアプローチは正しく、オーバーライドする必要があるという結論に達しました-bind:toObject:withKeyPath:options:
。Cocoa Bindings Programming Topics: How Do Bindings Work?からの引用です。:
bind:toObject:withKeyPath:options: メソッドでは、オブジェクトは少なくとも次のことを行う必要があります。
- 設定されているバインディングを特定する
- どのキーパスとどのオプションを使用して、どのオブジェクトにバインドされているかを記録します
- 変更の通知を受け取るために、バインドされているオブジェクトのキーパスのオブザーバーとして登録します
リスト 2 のコード サンプルは、角度バインディングのみを処理するジョイスティックの bind:toObject:withKeyPath:options: メソッドの部分的な実装を示しています。
リスト 2 ジョイスティック クラスの bind:toObject:withKeyPath:options メソッドの部分的な実装:
static void *AngleBindingContext = (void *)@"JoystickAngle"; - (void)bind:(NSString *)binding toObject:(id)observableObject withKeyPath:(NSString *)keyPath options:(NSDictionary *)options { // Observe the observableObject for changes -- note, pass binding identifier // as the context, so you get that back in observeValueForKeyPath:... // This way you can easily determine what needs to be updated. if ([binding isEqualToString:@"angle"]) { [observableObject addObserver:self forKeyPath:keyPath options:0 context:AngleBindingContext]; // Register what object and what keypath are // associated with this binding observedObjectForAngle = [observableObject retain]; observedKeyPathForAngle = [keyPath copy]; // Record the value transformer, if there is one angleValueTransformer = nil; NSString *vtName = [options objectForKey:@"NSValueTransformerName"]; if (vtName != nil) { angleValueTransformer = [NSValueTransformer valueTransformerForName:vtName]; } } // Implementation continues...
これは、Joystick クラス (NSView サブクラス) がオーバーライドする必要があることを明確に示しています-bind:toObject:withKeyPath:options:
。
これは驚くべきことです。これを実行するコード サンプルが他にないため、この結論には懐疑的でした。ただし、Apple の公式ドキュメントにはオーバーライドする必要があると記載-bind:toObject:withKeyPath:options:
されているため、これが正しいアプローチであると結論付けています。
誰かが私が間違っていることを証明できれば、とてもうれしいです!