Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

NSNotification subclass with Generics in Swift 2.1

Can't make subclass of NSNotification with Generic payload object. Getting either runtime error or compile error (see comments in code below). Is it even possible with Swift 2.1? Any ideas appreciated. Thanks!

Runtime error because NSNotification is abstract class (class cluster).
Compile error because designated initializer should be used.

public class Notification<T: Any>: NSNotification {

    private var _name: String
    private var _object: AnyObject?
    private var _payload: T?

    public override var name: String {
        return _name
    }

    public override var object: AnyObject? {
        return _object
    }

    public var payload: T? {
        return _payload
    }

    /// Always nil. Use payload
    public override var userInfo: [NSObject : AnyObject]? {
        return nil
    }

    /// Change to false to "swap" implementation
    #if true

    init(name: String, object: AnyObject? = nil, payload: T? = nil) {
        _name = name
        _object = object
        _payload = payload
        /*
          Runtime error:
          Terminating app due to uncaught exception
          'NSInvalidArgumentException', reason:
          '*** initialization method -initWithName:object:userInfo:
          cannot be sent to an abstract object of class
          _TtGC14__lldb_expr_1612NotificationSS_:
          Create a concrete instance!'
        */
        super.init(name: name, object: object, userInfo: nil)
    }

    #else

    convenience init(name: String, object: AnyObject? = nil, payload: T? = nil) {
        self.init()
        _name = name
        _object = object
        _payload = payload
    }

    init() {
        /// compiler error:
        /// must call a designated initializer of the superclass
        /// But using designated initializer cause runtime error listed above.
        super.init() 
    }

    #endif
}


let n = Notification<String>(name: "xyz", payload: "Hello")
like image 677
Vlad Avatar asked Dec 01 '15 21:12

Vlad


1 Answers

From the docs, emphasis mine:

You can subclass NSNotification to contain information in addition to the notification name, object, and dictionary. This extra data must be agreed upon between notifiers and observers.

NSNotification is a class cluster with no instance variables. As such, you must subclass NSNotification and override the primitive methods name, object, and userInfo. You can choose any designated initializer you like, but be sure that your initializer does not call [super init]. NSNotification is not meant to be instantiated directly, and its init method raises an exception.

There's no way subclass NSNotification from Swift code right now, as Swift has no concept of "uninitializable classes" and requires that all subclasses invoke their superclass's init (which, in this case, is the wrong thing to do).

You'll have to write the subclass in Objective-C and bridge it into your Swift code.

Unfortunately, even though you can declare your Objective-C class generic, that information is lost in the bridging process. From the docs:

Aside from these Foundation collection classes, Objective-C lightweight generics are ignored by Swift. Any other types using lightweight generics are imported into Swift as if they were unparameterized.

:(

like image 110
Ian Henry Avatar answered Sep 21 '22 14:09

Ian Henry