6

我有一个 NSView 子类,它具有我想要可绑定的属性。我在子类中实现了以下内容:

我的视图.h:

@property (readwrite, retain) NSArray *representedObjects;

我的视图.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 方法,则永远不会被调用。

附加信息:我进行了更多调查并得出结论,我的原始方法是正确的,您确实必须 override -bind:toObject:withKeyPath:options:。这是 Cocoa Bindings Programming Topics 中的一段话:Bindings 是如何工作的?

在其 bind:toObject:withKeyPath:options: 方法中,对象必须至少执行以下操作:

  • 确定正在设置的绑定
  • 使用什么键路径和什么选项记录它绑定到的对象
  • 注册为绑定对象的 keypath 的观察者,以便接收更改通知

清单 2 中的代码示例显示了操纵杆的 bind:toObject:withKeyPath:options: 方法的部分实现,该方法仅处理角度绑定。

清单 2 Joystick 类的 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:.

我觉得这很令人惊讶。我对这个结论持怀疑态度,因为我没有发现其他代码示例可以做到这一点。然而,正如苹果官方文档所说我应该超越-bind:toObject:withKeyPath:options:我的结论,这是正确的方法。

如果有人能证明我错了,我会很高兴的!

4

3 回答 3

1

不,你不应该需要那个胶水代码。

您所说的“似乎并非如此”是什么意思?如果你省略它会发生什么?

于 2008-12-14T21:06:26.183 回答
1

不,没有必要覆盖bind:.

正如 Peter Hosey 在对较早答案的评论中所写,您可以调用exposeBinding:和实现符合 KVC 和 KVO 的访问器和设置器。

我的视图.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

我的视图.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 中设置绑定,您必须创建一个自定义调色板。

于 2011-09-12T21:27:30.250 回答
0

如果您想在该视图中实现绑定,您肯定需要-bind:toObject:withKeyPath:options:在自定义视图中实现。您在 myView.m 中的实现非常准确。

于 2009-01-08T03:38:20.170 回答