How a Swift can fly through the Objective Sea (part 3): NSNotification reimagined with Generics.
In a previous story I wrote about how you can use swift to make a type-safe and generic notification system that can pretty much replace all uses of NSNotification.
However, if you are working professional, chances are that your code base is a blend of Objective-C and Swift, therefore any “swift-only” features are to be avoided. There is a solution of course. We must make the api compatible with swift and objective-c! But not just compatible, we must make the swift-facing side swifty!
Objective-c supports lightweight generics which is more like annotation then generics. Swift can use the annotation to infer the types. Let’s replace the swift-only solution with the objective-c equivalent.
The fact that it is written in Objective-c means that it is Objective-c compatible. It is also Swift Compatible. Here are the two ways that you can subscribe to the notification:
The notification object lives in the GenericNotificationCenter. It is a singleton that can be used to store instances of GenericNotification.
It is wonderful that the api is now available in both swift and objective-c. Now you can adopt GenericNotification without any worries!
There will of course be some people that will see that swift version and twitch upon seeing the use of NSString (me included). As of Swift 4, generic parameters do not automatically bridge. So whats the next best thing?
We can create an extension based on the generic types and manually bridge it for that specific type!
Because Objective-c can not infer the types at runtime we have to be very specific about the type. In our example the KEYTYPE is an NSString, the VALUETYPE is an NSString, and the RETURNTYPE is an NSNULL.
I specified NSNull because that is the closest objective-c equivalent to returning an object that represents Void. Therefore by using this extension, you may omit the NSNull part from the closure return type.
line 3 specifies the desired swift api. Ideally the callback’s first argument is a dictionary of type [String: String] and it returns void.
I still need to call the original objc api which is what I do on line 5. The objc api calls the swifty callback block and returns the appropriate return value. And now we can subscribe in the swifty way!