Search code examples
objective-cxcodemacosxcode4cocoa-bindings

What is needed to manually expose bindings on a custom NSView?


I have a NSView subclass that I want to expose a property (an NSGradient, to be exact) so I can bind it with other object (programatically using the bind:toObject:withKeyPath:options: method).

What steps should I take?

Here's what I done:

+(void)initalize {
  [self exposeBinding:@"gradient"];
}
- (Class)valueClassForBinding:(NSString*)binding {
  if ([binding isEqualToString:@"gradient"]) { return([NSGradient class]); }

  return(nil);
}
-(NSArray*)exposedBindings {
  return([NSArray arrayWithObjects:@"gradient",nil]);
}

I don't mind if the binding does not show in the Interface Builder. The gradient is a property implemented with @property (nonatomic, retain) NSGradient* gradient and it's working fine with the current implementation.

Is JUST the above code needed to implement that? (It seems too easy) I believe I'm missing something.

Note: I'm not a Bindings expert, but I do well on most of Objective-C.


Solution

  • The property to be bounded must be KVO and KVC compliant; that's in essence all that's necessary. Declaring the property the way you do and then @synthesizeing them or doing something equivalent is enough.

    bind:toObject:withKeyPath:options: is for some reason only one way, so you'll have to propagate values using KVC as Tom Dalling notes. Changes made on the receiver of the -bind:etc message have to be propagated manually.

    To my knowledge -exposeBinding: doesn't really do anything in Xcode 4 and is not necessary as IB no longer supports plugins. From the documentation:

    In most cases you need to use bind:toObject:withKeyPath:options:, and then only when you establish bindings programatically. Use of the unbind: is discussed in “Unbinding.” The other methods—the class method exposeBinding: and the instance methods exposedBindings and valueClassForBinding:—are useful only in an Interface Builder palette.

    To my knowledge the majority of the code you posted isn't necessary as long as you used -bind:toObject:withKeyPath:options:. You would keep that code to expose the binding in Interface Builder, but since we're in 2012 now and IB no longer has plugins...