KVO observation vs NSNotificationCenter observation - cocoa

I'm wondering if there is a reason to use one over the other in KVO vs NSNotificationCenter observations. Performance, memory usage, speed, etc?

The two are not always interchangeable. Conceptually, KVO is only for observing a property of an object. For example, you can't use KVO to replace NSApplicationWillTerminateNotification because it notifies observers about an event happening, not a change in a property of an object.
As for performance and memory usage, they are both fast and use negligible memory. NSNotificationQueue has coalescing to stop floods of notifications. KVO doesn't have any coalescing as far as I know, which did cause performance issues for me at one point. I was observing hundreds of objects, and when a batch update happened to those objects I'd get hundreds of KVO callbacks. It wasn't a performance issue with KVO itself, but with my own code running as a result of the batch update.
Performance isn't really the issue, it's more about the best fit for the problem. If it's a property change, use KVO. If it's not a property change, use a delegate or a notification depending on whether you need a single observer or multiple observers.

A very old question, but thought of adding some points. I agree with Tom Dalling's answer, however, there are many scenarios in big applications where we tend to add observer for a property of an object and we cannot, or, we miss out removing them from list of observers.
Let us consider the following scenario from my application - A ViewController displays a snake object, I am observing for a property change on this object - "venom". So whenever viewController needed to show a different snake I would simply remove the view controller from observer of that snake object.
The app evolved to show a list of snakes instead of a single snake, this means I had to observe for property of all snakes in that object. Now, when an old snake is removed from the array I should get to know about this event so that I can remove view controller as observer from this snake object. To do this, I have to first observe for changes on the array itself. To do this I have to follow particular protocol to insert objects into array and remove them from array. This way the complexity builds on. We all do know the consequences of not removing observer from an object and if that object is released by the OS!
Above is just one example to cite, the main problem here is I cannot get the list of KVO observers for a given object to remove them from observers before this object gets released - This can be easily achieved by NSNotification and NSNotificationCenter. At times, I tend to be inclined towards using NSNotification over KVO, however, KVO always has edge over notification in terms of good design practice.

Related

Dealing with NSManagedObjects when using MVVM

I've been struggling with a good answer to this one for a while:
How do you deal with NSManagedObjects as the Model in MVVM?
I've tried a few different approaches:
Retaining a copy of the NSManagedObject on the ViewModel — although this seems a bit dangerous to me, with the potential for threading issues
Unpacking the NSManagedObject into the properties I actually use on the VM via an -initWithModel: method — this would mean I no longer receive any updates to the NSManagedObject after the initial initialisation
Retaining a copy of the NSManagedObject's NSManagedObjectID, and using an NSManagedObjectContext specifically for each ViewModel instance to retrieve and monitor a private NSManagedObject and it's attributes — this seems a bit heavy to do this for every ViewModel instance (and potentially quite fragile)
None of these seem ideal. I have an idea in my head that it might be best to combine passing in an initial NSManagedObject instance via -initWithModel:, but only retaining the NSManagedObjectID, then listening for core data save notifications and weeding out any that don't relate to the retained object ID.
What I would do, and I don't know if this is necessarily the best practice, is pass in the model and then bind properties of the view model to (possibly mapped) properties on the model. That way you get updates through the view model. It does leave a little bit open to threading problems, but you can use deliverOn: to ensure that updates are always delivered on the main scheduler.

When to create a custom NSNotificationCenter?

I've been playing about with the NSNotificationCenter and I've been wondering when you would use your own custom notification center rather than the defaultCenter? And what would the advantages of this be?
Forgive my ignorance, but it seems like I could get along quite happily just using the defaultCenter and nothing else, but I want to make sure I am not missing something vital.
Apple documentation is vague, and it just states that usually a programmer wouldn't need to create a new one:
Each running Cocoa program has a default notification center. You typically don’t create your own. An NSNotificationCenter object can deliver notifications only within a single program.
Full source: NSNotificationCenter documentation.
However every notification center can handle a network of notifications, distinguished by name and object. When you add an observer you typically call the method in some way like this:
[center addObserver: self selector: #selector(observe:) name: #"observe" object: someObject];
And when you post a notification you can specify the object:
[center postNotificationName: #"observe" object: someObject];
This way say that you use N names and M objects, you can handle N*M distinguished notifications. I think there is no need to use two notification centers. Theoretically if you have finished all names you can create another one using alloc+init, but I hardly see how it can actually turn out handy.
Also consider that notification center is often used when there are two objects that do not own a direct pointer to each other (otherwise why not simply calling a method on it?), due to avoid complicated bindings (specially when you use a lot of xib files), so having an unique notification center object is very handy.
If instead you use a notification center got with allot+init, then you must ensure that all the communicating objects have a pointer to that notification center, and this would add some complexity. All notification center's power would be wasted.
Although it's used heavily in AppKit via the defaultCenter singleton accessor, at it's heart, NSNotificationCenter is really just a "generic decoupling mechanism." Allowing you to alloc/init your own instances of it is just an expression of that generic-ness. If you wanted to use it for something else, you could.
To illustrate with a somewhat absurd example, think of it this way: NSDocument has a windowControllers accessor that returns a specific, blessed, important instance of NSArray that contains references to all the window controllers specific to that document. That said, NSArray is just a "generic list data structure". Just because there exists this special instance of it with a specified purpose doesn't mean it might not be useful to reuse NSArray for your own purposes. Both NSArray and NSNotificationCenter provide generic data structures/building blocks, specific instances of which are used in blessed "occupations" around AppKit, but both of which could be useful on their own.
The primary use case I've seen for creating standalone instances of NSNotificationCenter is when you want to run multiple instances of some complex subsystem on multiple threads in parallel and not have them potentially get confused by cross-thread notifications. In this case, the general pattern is to allocate one NSNotificationCenter per thread. This compartmentalizes the notifications for each network of objects to a single thread. This will generally be required if observers pass nil for the object parameter intending to listen to all notifications with a given name, regardless of source.
All that said, I concede that, in my experience, making private instances of NSNotificationCenter is pretty rare.
Apple's Doc
If your app uses notifications extensively, you may want to create and post to your own notification centers rather than posting only to the default notification center. When a notification is posted to a notification center, the notification center scans through the list of registered observers, which may slow down your app. By organizing notifications functionally around one or more notification centers, less work is done each time a notification is posted, which can improve performance throughout your app.

What type of reference does NSNotificationCenter keep for 'observer's & 'object's?

Can anyone clarify/elucidate the situation with respect to -[NSNotificationCenter addObserver:selector:name:object:]?
What types of references are kept by the notification center of the 'observer' and 'object' arguments?
What are the best practices for removing observers from the notification center?
What are the special concerns for multi-threaded applications, especially with respect to the 'object' argument?
What are the differences in behavior of this method in GC and non-GC environments?
Are the any significant differences (from a client perspective) between mobile and desktop environments in this method's behavior?
Also, any pointers to existing articles which cover this would be greatly appreciated. I Googled, but was surprised to find little in-depth discussion of these issues (although maybe I didn't use the right magic keywords).
what types of references are kept by
the notification center of the
'observer' and 'object' arguments?
I believe a weak reference, though that's just from memory (no pun intended).
what are the best practices for
removing observers from the
notification center?
Always remove the registered object from the notification center before they're released. The object's dealloc method is a good place for this if it set up the registration itself, or when you release it if another object is managing the notification subscriptions. Keep this in mind and the above won't matter.
what are the special concerns for
multi-threaded applications,
especially WRT the 'object' argument?
NSNotificationCenter works fine on threads, but if you send a notification from a background thread, the object will receive it on that same thread. Because of this behavior you should use a different approach if you're updating the UI or doing anything else that's not thread safe (or, dispatch the notification from another method on the main thread).
what are the differences in behavior
of this method in GC and non-GC
environments?
I don't remember hearing of anything that you need to worry about, though I haven't used the GC much yet.
are the any significant differences
(from a client perspective) between
mobile and desktop environments in
this method's behavior?
Not that I've heard of, no. When you register your object you can choose to register for all notifications or only notifications from a certain object. If you're using notifications heavily the latter may be a little faster, but always test to be sure.
Also, any pointers to existing
articles which cover this would be
greatly appreciated. I googled, but
was surprised to find little in-depth
discussion of these issues (although
maybe i didn't use the right magic
keywords).
I think it's more because NSNotificationCenter is pretty easy to use, in general. If you're worried about certain cases, don't be afraid to write a quick test app!
Current situation in 2016:
iOS 9 has changed NSNotificationCenter such that it weak references the target object.
That also to say you no longer have to removeObserver in when the object is dealloc.

Threadsafe UITableView

I'm using a UITableView to show some data from an array. This array can be changed at any time by other threads. (I believe that whether the array is mutable, or just replaced entirely, doesn't make a difference.) Access to the array itself is threadsafe.
What's the proper way to ensure thread safety with regard to the tableview? I'm worried, for example, that I might change the array to be shorter just before cellForRowAtIndexPath is called, leading to an NSRangeException.
Should I...
Enforce that the array is only changed on the main thread? (Seems ugly.)
Maintain a shadow array and update this on the main thread through KVO observing?
??? There must be a better solution...
From your description, you really have TWO different data sets:
The actual data, as it exists in your model
The data that's displayed to the user
Thus, you already have, in effect, a 'shadow' array (virtual shadow, which may be stretching the metaphor too far). I'd say your best bet is to formalize this arrangement, and keep a 'display' array that only gets modified in the main thread. In it, you can have objects from your 'real' array; since they're only pointers, you won't be giving up too much memory.
Threading is evil.
Without knowing more about your app, I think one of the better solutions would be to keep the array on the main thread and dispatch back to it whenever another thread needs to make a change. Like this:
dispatch_async(dispatch_get_main_queue(), ^{
[array addObject:object];
[tableView reloadData];
});
Of course, you can get much more complex with the dispatch API, but it does handle locking and everything for you. Definitely more elegant than using an NSLock. It does only work on iOS 4 or later though.
I have the same situation. I have an array of C++ objects that provide the info in the tableview.
As Ben referred to, I also have a temporary "shadow" array into which new information is downloaded over the Internet. When the query is complete, I reconcile that array with the one backing the tableview, which is quite fast. The question is how to protect the array during that reconciliation.
I'm doing the reconciliation on the main thread, but I'm not sure that's sufficient to protect from conflicts, especially if the user taps on an entry while there's a query pending; the underlying object he's viewing details for might be blown away.
There's a similar question to yours (and mine) here:
Update UITableView using threads
but the answers berate the poster for taking too long with his background operation, instead of answering his question.
I'm going to use an NSLock, and acquire it before altering the array and in all of the UITableView delegate methods, unless somebody has a better idea.

In Cocoa do I need to remove an Object from receiving KVO notifications when deallocating it?

When I've registered an object foo to receive KVO notifications from another object bar (using addObserver:...), if I then deallocate foo do I need to send a removeObserver:forKeyPath: message to bar in -dealloc?
You need to use -removeObserver:forKeyPath: to remove the observer before -[NSObject dealloc] runs, so yes, doing it in the -dealloc method of your class would work.
Better than that though would be to have a deterministic point where whatever owns the object that's doing the observing could tell it it's done and will (eventually) be deallocated. That way, you can stop observing immediately when the thing doing the observing is no longer needed, regardless of when it's actually deallocated.
This is important to keep in mind because the lifetime of objects in Cocoa isn't as deterministic as some people seem to think it is. The various Mac OS X frameworks themselves will send your objects -retain and -autorelease, extending their lifetime beyond what you might otherwise think it would be.
Furthermore, when you make the transition to Objective-C garbage collection, you'll find that -finalize will run at very different times — and in very different contexts — than -dealloc did. For one thing, finalization takes place on a different thread, so you really can't safely send -removeObserver:forKeyPath: to another object in a -finalize method.
Stick to memory (and other scarce resource) management in -dealloc and -finalize, and use a separate -invalidate method to have an owner tell an object you're done with it at a deterministic point; do things like removing KVO observations there. The intent of your code will be clearer and you will have fewer subtle bugs to take care of.
A bit of extra info that I've gained by painful experience: although NSNotificationCenter uses zeroing weak references when running under garbage collection, KVO does not. Thus, you can get away with not removing an NSNotificationCenter observer when using GC (when using retain/release, you still need to remove your observer), but you must still remove your KVO observers, as Chris describes.
Definitely agree with Chris on the "Stick to memory (and other scarce resource) management in -dealloc and -finalize..." comment. A lot of times I'll see people try to invalidate NSTimer objects in their dealloc functions. The problem is, NSTimer retains it's targets. So, if the target of that NSTimer is self, dealloc will never get called resulting in some potentially nasty memory leaks.
Invalidate in -invalidate and do other memory cleanup in your dealloc and finalize.

Resources