Hacker Newsnew | past | comments | ask | show | jobs | submitlogin
NSNotificationCenter is Probably an Anti-Pattern (jaredsinclair.com)
22 points by aaronbrethorst on Jan 2, 2016 | hide | past | favorite | 13 comments


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.


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. :-/


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


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.


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).


In an app I'm working on currently I've opted to use 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.


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


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.


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.


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


(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.


But again, like the author said, they're pretty useful for truly global events from the OS itself. For instance, when the keyboard notification fires, it comes with useful information the app can use at runtime like xy coordinates involving the keyboard which can be used to make calculations on your views independent of the device size.

Edit: Sorry, just noticed your use of the qualifier "custom" there.


Code that relies on notifications for control flow is very hard to debug and reason about. Much better to set up explicit delegate/observer protocols between parts of your app that need to communicate with each other. You can use something like NSHashTable to manage weak references to a collection of observers that conform to your delegate protocol.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: