I'm trying to bind a property from a custom NSView to another on a custom NSObject. Both properties are simple bool value.
As a newbie with custom binding i've read Apple Documentation and searched on stackoverflow.
So I created a custom NSView and a custom NSObject, added a bool property called 'enabled' to both and bind them with [myCustomView bind:#"enabled" toObject:myObject withKeyPath:#"enabled" options:nil];
My customView use the approach explained in this article http://www.tomdalling.com/blog/cocoa/implementing-your-own-cocoa-bindings/ to notify value's changes and prevent memory retain issues.
I started my app, it works ! Wonderful ... but it's only one way binding ! When I click my customView, the custom object's property is updated (right) but if the custom object's property value change, my custom view's property isn't updated (Grrrr)
I'm a bit confused because as far as i understood custom bindings, Apple recommendation is to manually implement bind:toObject:withKeyPath:options and register an observer to track property's value changes and Tom Dalling's approach says the opposite.
So what is the best way to bind my properties in a bi-directional way ?
This SO answer here indicates that you just setup a symmetric binding going the other way. I haven't tried this, but it sounds like the following will work.
[myObject bind:#"enabled" toObject:myCustomView withKeyPath:#"enabled" options:nil];
I'm a bit confused because as far as i understood custom bindings, Apple recommendation is to manually implement bind:toObject:withKeyPath:options and register an observer to track property's value changes and Tom Dalling's approach says the opposite.
You have to implement both. You have to observe myObject with keypath #"enabled" so when myObject.enabled changes you can change myCustomView.enabled. You have to set myObject.enabled when myCustomView.enabled changes.
See Responding to Changes
Related
[self.toolController bind:#"fillColor" toObject:self.fillColorWell withKeyPath:#"color" options:kvoDict];
versus
[self.fillColorWell addObserver:self.toolController forKeyPath:#"color" options:NSKeyValueObservingOptionNew context:nil];
and in my toolController class, in my implementation for -observeValueForKeyPath:...
if( [keyPath isEqual:#"color"] ) {
self.fillColor = [object selectedObject];
}
Why would I pick one method over another to get the view to update to my model property?
For bindings the only code you have to write is for the bind itself and thats it. With KVO you would have to write to code to handle the notification. If your binding UI and using Interface Builder then you don't need any code at all, which can be useful / a time saver for the simpler things + you don't have to generic write boiler plate code to keep things is sync which you would to respond to the KVO notification.
I have read otherwise, but its my understanding (and I did a quick new project to verify this) that bindings are in both directions. So say if you bind a text field to an NSString, the variable changes when the textfield gets updated and you can change the variable and the text field updates. KVO would only notify you on the object you have specified the update for.
Some say bad things about bindings and that its good that they aren't part of iOS etc etc, but they work for the simple cases and so maybe you should just go with bindings until you find case where they are inappropriate. But having said if you want at some point to take your code over to iOS...
Hope thats a good enough answer for you :)
In my UICollectionViewCell subclass, I set the model and then observe a property on the model using KVO. I'm just not sure when the best place to remove the observer is.
I could remove it when the model is changed, but that means the observer will still be active when the cell is removed from the screen and put in the reuse queue. Similarly with -prepareForReuse
Is there a better place to put it than -viewWillMoveToSuperview:?
Don't know how I hadn't noticed it before, but the answer is to use -collectionView:didEndDisplayingCell:forItemAtIndexPath: on the UICollectionViewDelegate.
I have an entity with several properties, one of them called lastModificationDate. Whenever any of the object's properties is set, I'd like to update the lastModificationDate.
If I were not using Core Data, I would just provide my own setter for the properties and update lastModificationDate. However, I'm not sure if I should mess around with CoreData's properties.
What's the best way to do this?
Overriding the setters can easily be done, you have to make sure you fire the right notifications for everything else to work (including KVO).
- (void) setThing:(NSObject *)myThing {
self.lastUpdateDate = [NSDate date];
[self willChangeValueForKey:#"thing"];
[self setPrimitiveThing:myThing];
[self didChangeValueForKey:#"thing"];
}
This being said, if all you need to do is the code I showed (essentially setting the value and updating the last update date), you are much better off using Key-Value Observing and reacting to the notifications. It's easier and cleaner.
You shouldn't override property mutators (setters) if you're working with an NSManagedObject subclass because those implementations are provided at runtime (hence #dynamic instead of #synthesize). You could if you really wanted to, but it's messier and there's no reason to. Use Key Value Observing (KVO) instead. It'll let you know when a value is changed.
Apple's KVO documentation is great: https://developer.apple.com/library/mac/documentation/Cocoa/Conceptual/KeyValueObserving/KeyValueObserving.html#//apple_ref/doc/uid/10000177i
Heys,
I am writing something in Xcode. I use Core Data for persistency and link the view and the model together with Cocoa Bindings; pretty much your ordinary Core Data application.
I have an array controller (NSArrayController) in my Xib. This has its managedObjectContext bound to the AppDelegate, as is convention, and tracks an entity. So far so good.
Now, the "Content Set" biding of this NSArrayController limits its content set (as you'd expect), by a keyPath from the selection in another NSArrayController (otherAc.selection.detailsOfMaster). This is the usual way to implement a Master-Detail relationship.
I want to variably change the key path at runtime, using other controls. This way, I sould return a content set that includes several other content sets, which is all advanced and beyond Interface Builder.
To achieve this, I think I should bind the Content Set to my AppDelegate instead. I have tried to do this, but don't know what methods to implement. If I just create the KVC methods (objectSet, setObjectSet), then I can provide a Content Set for the Array Controller in the contentSet method.
However, I don't think I'm binding this properly, because it doesn't "refresh". I'm new to binding; what do I need to implement to properly update the Content Set when other things, like the selection in the master NSArrayController, changes?
However, I don't think I'm binding this properly, because it doesn't "refresh".
This most often means you are assigning directly to the instance variable, not using KVC-compliant accessor methods nor posting KVO notifications.
The general solution is to create accessor methods for the property and then use them everywhere, including inside that class, except in its init and dealloc methods.
I was wondering if it is possible at run-time to dynamically add new properties to an Objective-C object instance?
My initial thought would just to overrride the getValueForKey to "fake" a property but it seems like this doesn't work with CoreAnimation. What I want to achieve is to be able to animate custom properties. I have been able to get that to work if I create a subclass of CALayer and add declared properties to my subclass. If I try to use the getValueForKey/setValueForKey strategy it seems like CoreAnimation doesn't care for that and it is explicitly looking for declared properties.
I would like to be able to dynamically add the properties because I might not know what property I want to animate until runtime. I can of course create a CALayer subclass that has all the properties that I would ever want to animate...but just wondering if there is a nicer way to do this...
Thanks,
Peter
Have you tried overriding valueForUndefinedKey: instead? (I do this on a custom NSObject subclass that can have various properties whose names are pulled from a database.)
You could override -respondsToSelector: and -doesNotUnderstand: to process incoming messages dynamically if need be.