
NSNotificationCenter is Probably an Anti-Pattern - aaronbrethorst
http://blog.jaredsinclair.com/post/136408895215/nsnotificationcenter-is-probably-an-anti-pattern
======
jakobegger
The problem of messages sent to deallocated objects isn't unique to
NSNotifications, the same thing can happen with calls to delegates[1]. This
problem can easily be solved by (a) using weak references, or (b) by searching
your code for "addObserver" and making sure there is a matching
"removeObserver" for every call.

While I agree with the author that often delegates are a nicer pattern, I
wouldn't go as far as calling NSNotificationCenter an anti-pattern. I also
think that limiting its use to global notifications is not good advise.

My advise for using NSNotifications is whenever you want loose coupling
between objects.

For example, I have an app that displays an iTunes-like status view at the top
of the window. I don't want all the query objects and the status view tightly
coupled. Instead, my query objects post notifications when the status changes,
and the status view observes them. Using notifications lets me separate
concerns, and avoid coupling between model and view layers.

Also, another powerful feature of NSNotifications is that an observer can
decide on its own when it is no longer interested in notifications. When you
have block-based completion handlers, there's usually no way to unregister a
completion handler. This can lead to crashes as well, when a long-running
request times out after the user has already closed the window.

[1]: There was a pretty severe bug in OS X 10.10 that caused views to be
retained after their window was closed, so that many apps all of the sudden
crashed when the views sent messages to their delegates which were
deallocated. A workaround was to make sure to make sure that controllers call
setDelegate:nil on their views in the dealloc method -- just like with
NSNotificationCenter.

~~~
Flow
I have about a million of these and similar log entries:

    
    
        WindowServer: _CGXRemoveWindowFromWindowMovementGroup: window 0x1d is not attached to window 0x4d
    

My El Capitan installation is fresh. Didn't help. I think reading the logs in
OS X since Yosemite, does make OS X feel buggy and it should probably not work
as well as it does. :-/

~~~
arthurcolle
Sorry, total outsider to OS X/iOS programming. What logs are you referring to?
Just curious

------
nathanvanfleet
Not really much of a strong argument. Notifications, KVO and delegation are
indeed the methods that are typically used. I don't really think he's making a
strong argument not to ever use NSNotifications, though I'd agree they should
ideally be bigger stuff related to application state changes.

Delegate is probably the most fool proof way to do it and is pretty much
protected by the compiler to give you the warnings you might need and doesn't
require much template. But ultimately there are a lot of things where it's
frankly a one to many scenario and delegation is out of the picture.

I suppose I've continually grappled fixing both bugs in KVO and
NSNotification, and it seems like Notifications are much easier to find by
just searching for the const string to audit the observers. KVO is tricker
especially if there are keypaths and what if the name of the property is
changed? The whole thing happens in the runtime so it's basically a nightmare.

So ultimately yeah, you can clean up KVO and make a better implementation.
I've written something that makes a intermediary object that managed some of
the trickier aspects of KVO (having to call super and pass a context and
dealloc etc). But now I'm at a new place and I wouldn't put the effort into
getting everyone on board into using that code instead of the usual Foundation
stuff.

~~~
themartorana
Academically the article may hold water, but I tend towards your thinking.
There are just as many articles that will declare the values of loosely
coupled systems as there are for tightly-coupled. The truth is, most software
of any size is a combination of the two.

In many cases, directly-related pieces should probably have a tight
understanding of what's happening with their neighbor or ancestor or
descendant, and delegates are great for this. But sometimes, I want my
software to announce that certain things have happened, or completed, or
whatever, and _not_ care who, if anyone, is listening, and
NSNotificationCenter is brilliant for this. For instance, a top-level UI
feature like an indeterminate progress indicator doesn't need to know of every
single bit of work being performed by lower levels of the software, and
tightly coupling them - even along a delegate chain of some sort - is fraught
with potential edge cases. Simply listening for start and end announcements
means dozens of not hundreds of lines of code eliminated, and maintaining a
crazy delegate chain unnecessary.

In any case, I've found this pattern extremely helpful and useful, and is one
of my favorite bits of working with Objective-C (and now Swift).

------
Moto7451
In an app I'm working on currently I've opted to use
[https://github.com/slazyk/Observable-
Swift](https://github.com/slazyk/Observable-Swift) instead of KVO and
NSNotificationCenter. So far I've been pretty pleased by the experience and I
hope something like this works its way into the ecosystem.

~~~
seivan
Look into RxSwift. You'd get the same API in Ruby, JS and other languages as
they try to follow the same documentation outline.

------
stevedekorte
Notifications are appropriate when you have multiple listeners which is so
common that (fwiw) I'd like to see delegates replaced with some more elegant
form of notifications that can also carry trace info for debugging.

------
seivan
It is an anti-pattern. I hate when apps push notification a cross controllers.
Pub/Sub should only be used internally like a ECS pushing update, add, remove
and other callbacks.

------
fleitz
Very much agree, almost every time I've seen custom notifications they've been
a huge source of pain across the app.

~~~
amm
(Global) notifications are sometimes the only sane way to deliver a message
from one part of your application to another one without explicitly wiring
them together. If you're working with some kind of plugin system they're also
incredibly useful to deliver state updates to plugged-in components.

Once your codebase reaches a certain size, an event bus is a very powerful
pattern that, if applied correctly, will keep your classes/functions/...
decoupled.

Naturally, there is a huge potential for misuse, but that argument probably
applies to any design pattern.

