When to create a custom NSNotificationCenter? - cocoa

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.

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.

How to get Core Data to make only one instance of entity of type

So. Before I get singleton pattern hate on this message hear me out. I'd love to hear ideas. I'm making a program that I think I need to use core data for, because later I want the status of some variables to be easily accessible from OS X, and multiple iOS devices.
What I'm making is an OS X program that will control phidgets (phidgets.com) to control and listen for status changes in real world objects. Example: whether a motor is turned on or not. Turn a motor on and off. Turn on status lights, etc.
I originally thought I'd just make global variables that I change, poll and manipulate in order to have a central status board for the logic of the program to work off of. But, because of the engineering that is put into core data every year by apple, I am assuming making this work with core data will allow me to more easily have options to sync this later with iOS devices that could control or monitor the said status' remotely.
Is there a nifty way you can imagine to:
-startup the program, confirm there is only one entity of type "SystemStatus", if there isn't one, make one. is there is one, we continue and are able to let the program update it's attributes with status of the real world objects it's controlling.
using core data was something I thought of also, because it will allow me a place to persist stored history of data gathered too. Example: motor bearing temperature over time.
If you ensure that access to this object is done through your API, Core Data becomes an implementation detail behind the getter method of the singleton object. There are no facilities in Core Data to tell it to create only one object, but if you ensure access to the object is done through a wrapper of your own, you can fetch it on demand and if it doesn't exist, you can insert it, save, and pass it to the caller.
An important thing to consider when using Core Data objects is multithreading. Passing the same object to multiple threads is very error-prone and requires locking mechanisms (or use of Apple's block-based API). This is not very straightforward for what you describe. Consider either a wrapper object which uses Core Data objects internally (wraps access to properties in block-based API) or using a different approach than Core Data.

When does NSSpeechSynthesizer finish speaking?

How can I know when NSSpeechSynthesizer finishes speaking?
You read the documentation for NSSpeechSynthesizer and discover the -speechSynthesizer:didFinishSpeaking: delegate method.
Then, if you're not sure how to use delegate methods, you read more documentation about Cocoa delegates.
Then, if you still can't get it to work, you post a separate question here including as many details as you can about what you've tried (hint: code, a description of your app and how things are connected, etc.) and what isn't working (ie, the delegate method is never called, it crashes, etc.).

KVO observation vs NSNotificationCenter observation

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.

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.

Resources