问题描述
我有一个NSView子类,它有我想要绑定的属性。我在子类中实现了以下内容:
I have an NSView subclass which has property which I want to be bindable. I've implemented the following in the subclass:
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]
:
I then create the binding to an arrayController in -[AppController awakeFromNib]
:
[myView bind:@"representedObjects" toObject:arrayController withKeyPath:@"arrangedObjects" options: nil];
这是正确的实现绑定的方式吗?它涉及到大量的锅炉板代码,这让我认为我做错了。
Is this the correct way of implementing binding? It involves a lot of boiler plate code which makes me think that I'm doing something wrong.
我认为NSObject会自动实现我在 -bind:toObject:withKeyPath:options:
但这似乎不是这样的。如果我注释掉我的 -bind:toObject:withKeyPath:options:
,则不会调用setRepresentedObjects方法。
I thought that NSObject would automagically implement what I have done manually in -bind:toObject:withKeyPath:options:
but this doesn't seem to be the case. If I comment out my -bind:toObject:withKeyPath:options:
the setRepresentedObjects method is never called.
info:
我做了一些更多的调查,并得出的结论,我的原始方法是正确的,你必须超过 -bind:toObject:withKeyPath:options:
。以下是来自:
Additional info:I've done some more investigating and have reached the conclusion that my original approach is correct and you do have to over ride -bind:toObject:withKeyPath:options:
. Here's a quote from Cocoa Bindings Programming Topics: How Do Bindings Work?:
- 确定要设置的绑定
- 注册为其绑定对象的键值的观察者,以便接收更改通知 $ b $ b
- Determine which binding is being set
- Record what object it is being bound to using what keypath and with what options
- Register as an observer of the keypath of the object to which it is bound so that it receives notification of changes
清单2中的代码示例显示了Joystick的bind:toObject:withKeyPath:options:方法仅部分实现角度绑定。
The code sample in Listing 2 shows a partial implementation of Joystick’s bind:toObject:withKeyPath:options: method dealing with just the angle binding.
清单2 Joystick类的bind:toObject:withKeyPath:options方法的部分实现:
Listing 2 Partial implementation of the bind:toObject:withKeyPath:options method for the Joystick class:
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: code>。
This clearly shows that the Joystick class (which is an NSView subclass) needs to override -bind:toObject:withKeyPath:options:
.
我觉得这很奇怪。我对此结论持怀疑态度,因为我没有找到任何其他代码样本来做到这一点。但是,正如苹果文档中所说,我应该过 -bind:toObject:withKeyPath:options:
我认为这是正确的方法。
I find this surprising. I was skeptical of this conclusion as I have found no other code samples that do this. However, as the offical Apple documentation says I should over ride -bind:toObject:withKeyPath:options:
I conclude that it is the correct approach.
如果有人可以证明我错了,我会很高兴。
I would be very happy if someone could prove me wrong!
推荐答案
不,必须重写 bind:
。
正如Peter Hosey在前面的回答中写道, code> exposeBinding:并实现符合KVC和KVO的访问器和设置器。
As Peter Hosey wrote in the comment to the earlier answer, you can call exposeBinding:
and implement KVC- and KVO-compliant accessors and setters.
MyView.h: strong>
MyView.h:
@interface MyView : NSView {
NSArray *_representedObjects;
}
// IBOutlet is not required for bindings, but by adding it you can ALSO use
// an outlet
@property (readonly, retain) IBOutlet NSArray *representedObjects;
@end
MyView.m:
+ (void)initialize {
[self exposeBinding:@"representedObjects"];
}
// Use a custom setter, because presumably, the view needs to re-draw
- (void)setRepresentedObjects:(NSArray *)representedObjects {
[self willChangeValueForKey:@"representedObjects"];
// Based on automatic garbage collection
_representedObjects = representedObjects;
[self didChangeValueForKey:@"representedObjects"];
[self setNeedsDisplayInRect:[self visibleRect]];
}
然后你可以通过编程方式设置绑定:
Then you can set the binding programmatically:
[myView bind:@"representedObjects" toObject:arrayController withKeyPath:@"arrangedObjects" options: nil];
但是,要在Interface Builder中设置绑定,必须创建自定义调色板。
To set the binding in Interface Builder, however, you must create a custom palette.
这篇关于是否有必要重写bind:toObject:withKeyPath:options:在NSView子类中实现绑定?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!