我有一个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]];
}
}
然后我在-[AppController awakeFromNib]
中创建了对arrayController的绑定:
[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:方法中,对象必须至少执行以下操作:
- 确定正在设置的绑定
- 使用什么键路径和哪些选项
记录它绑定的对象- 注册为绑定对象的keypath的观察者,以便收到更改通知
清单2中的代码示例显示了Joystick的bind的部分实现:toObject:withKeyPath:options:只处理角度绑定的方法。
清单2部分实现bind:toObject:withKeyPath:Joystick类的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:
。
我觉得这很令人惊讶。我对此结论持怀疑态度,因为我没有找到其他代码示例。但是,正如苹果公司的官方文档说我应该过度-bind:toObject:withKeyPath:options:
我得出结论认为这是正确的方法。
如果有人能证明我错了,我会很高兴的!
答案 0 :(得分:1)
不,你不应该需要胶水代码。
你的意思是“似乎并非如此”?如果省略它会怎么样?
答案 1 :(得分:1)
不,没有必要覆盖bind:
。
正如Peter Hosey在前面回答的评论中写道,您可以致电exposeBinding:
并实施符合KVC和KVO标准的访问者和设置者。
<强> 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]];
}
然后您可以以编程方式设置绑定:
[myView bind:@"representedObjects" toObject:arrayController withKeyPath:@"arrangedObjects" options: nil];
但是,要在Interface Builder中设置绑定,您必须创建自定义调色板。
答案 2 :(得分:0)
如果要在该视图中实现绑定,您肯定需要在自定义视图中实现-bind:toObject:withKeyPath:options:
。您在myView.m中的实现非常适合。