Re: Trouble binding against transient Core Data property
Re: Trouble binding against transient Core Data property
- Subject: Re: Trouble binding against transient Core Data property
- From: Quincey Morris <email@hidden>
- Date: Sun, 10 Oct 2010 22:31:47 -0700
On Oct 10, 2010, at 21:52, Rick Mann wrote:
> @dynamic shadowFrame;
>
> "frame" is a transient Core Data property of Undefined Type, but it's an NSRect in the class file. Its implementation:
>
> - (NSRect)
> frame
> {
> [self willAccessValueForKey:@"frame"];
> NSString* v = self.shadowFrame;
> [self didAccessValueForKey:@"frame"];
> NSRect nsR = NSRectFromString(v);
> return nsR;
> }
The Core Data programming guide is a bit hard to follow on this subject (because it talks about the difficult cases and not the easy cases), but I *think* this is an unnecessary approach. Just don't put "frame" in the Core Data model at all, and let it be a regular property. The implementation is the same as you've got, except that you don't need the willAccess/didAccess/wiilChange/didChange calls. OTOH, I *think* what you did should work fine. I'm pretty sure this is nothing to do with your problem.
On Oct 10, 2010, at 21:52, Rick Mann wrote:
> VisualizationPlugIn* vp = ...;
> NSView* view = vp.displayViewController.view;
> [vp bind: @"frame" toObject: view withKeyPath: @"frame" options: nil];
>
> I may not really fully understand bindings, in the sense that I don't know what you mean about NSView not having a "frame" binding. The docs imply that you can only call -bind:... on a binding that you've called -exposeBinding:... on, but someone at Apple told me that you only need to call -exposeBinding:... for IB's sake.
It's more complicated than that. 'exposeBinding...' is necessary only for IB's sake, so it's basically irrelevant to this discussion.
However, a binding -- a real, honest-to-goodness Cocoa binding -- needs support code in the class that defines the binding. This support code essentially makes sure that the bound object are updated in both directions. For *one* of the directions (from the bound object to the bound-to object), the standard implementation of 'bind:toObject:withKeyPath:options:' in NSObject is normally perfectly adequate. The other direction is custom code in the class providing the binding.
So, when I said NSView doesn't have a "frame" binding, I meant it doesn't have this custom code for a binding named "frame". (It does have the code for a binding named "toolTip", for example.)
Under these circumstances, when you call [object1 bind:@"xyz" toObject: object2 withKeyPath:@"abc" options:...], all you get is object1's KVC-compliant property "xyz" following object2's "abc" property, but not vice versa. In that sense, this is not about bindings at all -- 'bind...' serves merely as a convenient way to set up a uni-directional KVO observance.
In your case, you reversed the order of the objects -- you "bound" the plugin's "frame" property to the view's "frame" property. In other words, you told your plugin object to KVO observe the view, and nothing more. That's why moving the view changes the model. But since it's uni-directional, changing the model (e.g. via undo) doesn't change the view.
If this sounds confusing, it is. The term "binding" is essentially ambiguous is very non-trivial way. That's why I strongly object to using 'bind...' for mere KVO observance -- it obscures the real operation of the bindings mechanism.
In summary, you've:
1. "bound" in the wrong direction -- you should have attempted to bind from the view to the data model (plugin)
2. failed to establish a "frame" binding because none of the classes involve has a "frame" binding (just a "frame" property, which is insufficient for your purposes)
3. set up a one-way KVO observance that provides precisely half the functionality you want
One way or another, you're going to have to come up with code to handle both directions of frame change: model-to-view and view-to-model. One approach is to use KVO observance (via [view bind:@'frame" toObject:vp withKeyPath:@"frame" options:0] if you really want to -- note the change of direction) for one direction, and have a controller object (such as a view controller or window controller) observe frame-change notifications from the view and update the model property directly.
Or something like that.
_______________________________________________
Cocoa-dev mailing list (email@hidden)
Please do not post admin requests or moderator comments to the list.
Contact the moderators at cocoa-dev-admins(at)lists.apple.com
Help/Unsubscribe/Update your Subscription:
This email sent to email@hidden