NSNotification VS KVO - objective-c

I feel that i don't fully understand difference between KVO and NSNotification... They seem to be so similar...
Could you make some example showing when is best to use one method and when the other ?
I don't speak about Bind and IB, but i mean add Observer programmatically in my code with NSNotificationCenter or KVO
[self.preferenceController addObserver:self
forKeyPath:#"color"
options:NSKeyValueObservingOptionOld
context:#"Color-change"
];

KVO only works on values, NSNotification can be used for value changes but it can be used for anything and can carry a much greater payload.
For example, you could have an NSNotification posted whenever a file has finished downloading and the userInfo could contain the length of time it took, the number of bytes downloaded and the filesystem path that the file has been saved to.

Related

Cocoa Bindings, should I just be using KVO instead?

[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 :)

NSManagedObjectContextDidSaveNotification best way to update the UI?

In my code i have an mainManagedObjectContext and a backgroundManagedObjectContext and its working great.
I moved all my save code to the backgroundManagedObjectContext and merging the differences between the contexts via NSManagedObjectContextDidSaveNotification.
Now I want to update my UI after NSManagedObjectContextDidSaveNotification. What is the best approach beside of a NSFetchedResultController to do this?
The changes in my object is visible via the debugger and I could use KVO for this, but IMHO it's a terrible idea. In my abstraction i got a Model to handle the database calls and it would be great when my Model also handling changes after merging the context.
What is the best approach to do this?
As has been pointed out, for table and collection views, the best bet is NSFetchedResultsControllerDelegate.
Another mechanism is to register for this (or your custom) notification NSNotificationCenter, e.g. for the original notification:
[[NSNotificationCenter defaultCenter]
addObserver:self
selector:#selector(updateUI:)
name:NSManagedObjectContextDidChangeNotification
object:nil];
Best do this in viewDidAppear. Don't forget to remove the observer in viewWillDisappear. Note that following the comment I am using the change notification rather than the save notification.
In your non-table view controllers you should isolate the UI setup, similar to the boilerplate code for the fetched results controller delegate, which implements a method like configureCell:atIndexPath:. You can then simply call this setup routine when you get the notification without duplicating any code.

Change notification for self in NSMutableDictionary subclass

I've subclassed NSMutableDictioary following mainly this great blog post.
Now in that subclass the dictionary itself subscribes to all its values in order to detect any changes. This bit works just fine and value changes are observed internally in that subclass.
However value changes should then be propagated to observers of the dictionary, i.e. observers of the dictionary (subclass) are supposed to get notified that the dictionary has changed.
Except I cannot figure out how to trigger that KVO notification - using
[self didChangeValueForKey:#"self"];
doesn't seem to have any effect so I'm kinda stuck.
How can an instance of the NSMutableDictionary subclass initiate a change notification for itself?
As already hinted by Ken KVO allows you to observe properties - not an object per se!
The Key-Value Observing Programming Guide states, that
Key-value observing provides a mechanism that allows objects to be notified of changes to specific properties of other objects.
In other words: self can never be observed.

Reactive NSMutableDictionary?

How do I subscribe to objects being added and removed from a NSMutableDictionary using ReactiveCocoa? Also, I'd like to broadcast a notification when it changes. My guess is that broadcasting can be done using RACMulticastConnection but how do I tie this up with the dictionary change? I'm trying to use ReactiveCocoa for the first time in my project and stuck on the first thing I wanted to do :(
RACObserve is a wrapper around key-value observing, and inherits the same features and flaws.
Unfortunately, NSMutableDictionary is not automatically observable. There are two ways to work around that:
Subclass it and add KVO support.
Create a real model object, with properties instead of dictionary keys. Then you'll get KVO on those properties, as long as you use setters instead of direct ivar modification.
I'm not sure exactly what you mean by "[broadcasting] a notification when it changes," or why it'd be valuable. Notifications are way too global for my taste, and I'd promote using more limited observation instead (like KVO).
However, assuming you definitely want to do this, it's simple enough to post a notification in response to a new signal value:
#weakify(self);
[RACObserve(self, dictionary) subscribeNext:^(NSDictionary *dictionaryValue) {
#strongify(self);
[NSNotificationCenter.defaultCenter postNotificationName:SomeNotificationName object:self];
}];
If you want KVO's change dictionary (which includes information about the added/removed values), you'll need to replace RACObserve with +rac_valuesAndChangesForKeyPath:options:observer:.
every time you set or remove the key-value,reset the dict,so you can observer the dict.
just like:
[RACObserve(self, testDict) subscribeNext:^(id x) {
NSLog(#"RACObserve testDict:%#",x);
}];
[self.testDict setObject:value forKey:key];
self.testDict=self.testDict;

Bindings AND target/action?

I currently have a color well which keeps track of a color that gets saved in the NSUserDefaults. It is bound to an NSUserDefaultsController. However, I also want to listen for changes to the color so I can update my views accordingly. Therefore, in addition to the binding, I added a target/action to the color well to my preferences controller that posts a notification with the color.
1) How safe is having both target/action and bindings? Is there a possibility that one might lag or they may be out of sync and report different values?
2) When I am getting the color in my IBAction method, should I get it from the user defaults or from the color well?
Here is my colorChanged: action:
- (IBAction)colorChanged:(id)sender
{
NSDictionary *userInfo = [NSDictionary dictionaryWithObject:[colorWell color] forKey:#"color"];
[notificationCenter postNotificationName:#"ColorChangedNotification" object:self userInfo:userInfo];
}
So should I be doing this:
[NSKeyedUnarchiver unarchiveObjectWithData:[[NSUserDefaults standardUserDefaults] objectForKey:#"color"]];
or:
[colorWell color];
Thanks!
1) How safe is having both
target/action and bindings? Is there a
possibility that one might lag or they
may be out of sync and report
different values?
I think for the most part, it should be OK. The best way to tell is to test it out.
2) When I am getting the color in my IBAction method, should I get it from the user defaults or from the color well?
You should definitely, definitely get it directly from the color well. Why? There could be a lag when saving to the user defaults. Heck, the defaults could even save only once right before the application terminates, and it would still be alright. (OK, this isn't entirely true, but still) The defaults' main purpose is to persist data in between application launches, not during the lifespan of the app.
It is safe to have both target/action and bindings. If you post notifications with an NSNotificationCenter, then the notifications are delivered synchronously to the observers. (With the obvious caveat that it is not magic--if observer A sends a message to observer B when it gets the notification, observer B will not have received the notification yet. Multiple threads add further complexity.) This is called out in the documentation for NSNotificationCenter.
Reading the color directly from the color well is fast, and probably fine from an IBAction. If you're running code when the application is starting it is best to read from the user defaults because the color well's bindings might not have been updated yet.