NSNotificationCenter with Swift

Working with NSNotifciationCetner in Swift is fairly straightforward.

// This class will correctly work because it inherits from
// NSObject and thus automatically can be used by Objective-C.
// It does not use any Swift specific features.
class OkExample: NSObject {

    override init() {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "handler:", name: "MyNotification", object: nil)

    func handler(notif: NSNotification) {
        println("MyNotification was handled")

Take for instance the example shown above. This class will work correctly with NSNotificationCenter because the class inherits from NSObject (you can also mark your class with the @objc).

We can easily call emit this notification by using notification center.

NSNotificationCenter.defaultCenter().postNotificationName("MyNotification", object: nil);  

That's all well and good, but what happens if your class uses Swift specific features. Well it won't work. Consider the following:

// This class will not work becuase it users the Swift
// specific feature of Generics. As a result, Objective-C will
// be unable to find the `handler` method resulting in a runtime exception
class BadExample<T>: NSObject {

    override init() {
        NSNotificationCenter.defaultCenter().addObserver(self, selector: "handler:", name: "MyNotification", object: nil)

    func handler(notif: NSNotification) {
        println("MyNotification was handled")

In Swift and Objective-C in the Same Project it mentions a few caveats that have an impact on how selectors can be used from Objective-C code.

You’ll have access to anything within a class or protocol that’s marked with the @objc attribute as long as it’s compatible with Objective-C. This excludes Swift-only features such as:

  • Generics
  • Tuples
  • Enumerations defined in Swift
  • Structures defined in Swift
  • Top-level functions defined in Swift
  • Global variables defined in Swift
  • Typealiases defined in Swift
  • Swift-style variadics
  • Nested types
  • Curried functions

The end result, is that if you attempt to use NSNotificationCenter

2014-12-04 20:56:50.271 iOSExamples-ModelSync[4360:149860] -[_TtC21iOSExamples_ModelSync10BadExample00007F8DB3456710 handler:]: unrecognized selector sent to instance 0x7f8db3455360  
2014-12-04 20:56:50.281 iOSExamples-ModelSync[4360:149860] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[_TtC21iOSExamples_ModelSync10BadExample00007F8DB3456710 handler:]: unrecognized selector sent to instance 0x7f8db3455360'  
*** First throw call stack:
    0   CoreFoundation                      0x000000010eb69f35 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x00000001106adbb7 objc_exception_throw + 45
    2   CoreFoundation                      0x000000010eb7104d -[NSObject(NSObject) doesNotRecognizeSelector:] + 205
    3   CoreFoundation                      0x000000010eac927c ___forwarding___ + 988
    4   CoreFoundation                      0x000000010eac8e18 _CF_forwarding_prep_0 + 120
    5   CoreFoundation                      0x000000010eb39cec __CFNOTIFICATIONCENTER_IS_CALLING_OUT_TO_AN_OBSERVER__ + 12
    6   CoreFoundation                      0x000000010ea398a4 _CFXNotificationPost + 2484
    7   Foundation                          0x000000010ef426b8 -[NSNotificationCenter postNotificationName:object:userInfo:] + 66
    8   iOSExamples-ModelSync               0x000000010e971d9e _TFC21iOSExamples_ModelSync11AppDelegate11applicationfS0_FTCSo13UIApplication29didFinishLaunchingWithOptionsGSqGVSs10DictionaryCSo8NSObjectPSs9AnyObject&#95;&#95;&#95;&#95;Sb + 1278
    9   iOSExamples-ModelSync               0x000000010e9720b0 _TToFC21iOSExamples_ModelSync11AppDelegate11applicationfS0_FTCSo13UIApplication29didFinishLaunchingWithOptionsGSqGVSs10DictionaryCSo8NSObjectPSs9AnyObject&#95;&#95;&#95;&#95;Sb + 560
    10  UIKit                               0x000000010f3f0475 -[UIApplication _handleDelegateCallbacksWithOptions:isSuspended:restoreState:] + 234
    11  UIKit                               0x000000010f3f0fbc -[UIApplication _callInitializationDelegatesForMainScene:transitionContext:] + 2463
    12  UIKit                               0x000000010f3f3d2c -[UIApplication _runWithMainScene:transitionContext:completion:] + 1350
    13  UIKit                               0x000000010f3f2bf2 -[UIApplication workspaceDidEndTransaction:] + 179
    14  FrontBoardServices                  0x000000011223a2a3 __31-[FBSSerialQueue performAsync:]_block_invoke + 16
    15  CoreFoundation                      0x000000010ea9f53c __CFRUNLOOP_IS_CALLING_OUT_TO_A_BLOCK__ + 12
    16  CoreFoundation                      0x000000010ea95285 __CFRunLoopDoBlocks + 341
    17  CoreFoundation                      0x000000010ea95045 __CFRunLoopRun + 2389
    18  CoreFoundation                      0x000000010ea94486 CFRunLoopRunSpecific + 470
    19  UIKit                               0x000000010f3f2669 -[UIApplication _run] + 413
    20  UIKit                               0x000000010f3f5420 UIApplicationMain + 1282
    21  iOSExamples-ModelSync               0x000000010e97236e top_level_code + 78
    22  iOSExamples-ModelSync               0x000000010e9723aa main + 42
    23  libdyld.dylib                       0x0000000110e87145 start + 1
    24  ???                                 0x0000000000000001 0x0 + 1
libc++abi.dylib: terminating with uncaught exception of type NSException  

The solution I came up with is to use a proxy class that will listen to NSNotificationCenter events and execute a closure upon observing that notification. The closure, becuase it is part of Swift can execute for any Swift class.

/// Provides proxy functionality for NSNotificationCenter
/// events for Swift classes that do not support integration
/// with Objective-C code.
@objc class ObserverProxy {

    var closure: (NSNotification) -> ();
    var name: String;
    var object: AnyObject?;

    init(name: String, closure: (NSNotification) -> ()) {
        self.closure = closure;
        self.name = name;


    convenience init(name: String, object: AnyObject, closure: (NSNotification) -> ()) {
        self.init(name: name, closure);
        self.object = object;

    deinit {

    func start() {
        NSNotificationCenter.defaultCenter().addObserver(self, selector:"handler:", name:name, object: object);

    func stop() {

    func handler(notification: NSNotification) {

Then, your Swift class can use this proxy class to listen for events.

// This class uses a proxy class that will listen for the notification.
// When the notification is fired, the proxy class will execute the supplied
// closure... which happens to be the handler on this class. This structure allows
// us to get around the limitation of Objective-C not having access to the methods
// in a Generic class
class ProxyExample<T>: NSObject {

    var myNotificationProxy: ObserverProxy?;

    override init() {
        myNotificationProxy = ObserverProxy(name: "MyNotification", closure: handler);

    func handler(notif: NSNotification) {
        println("MyNotification was called")

This technique could be modified to provide a cleaner syntax to allows more than a single closure to be applied to a single proxy. But this should help you get around limitations with Swift specific features preventing NSNotificationCenter from working.

comments powered by Disqus