Dealing with NotificationCenter is daily task for all iOS developers. Either it’s a system notification such as KeyboardShow/KeyboardHide or CustomNotification to post some information app wide, we all have used Notifications.
Yeah, So. Do you have something interesting to say?
Well, answer to that question is, Yes. Today, we are gonna discuss notification programming in such a way, that it will become as easy as eating an apple pie. (I don’t think anyone can deny it, eating an apple pie is just so satisfying, obviously if you love apple pie in first place ;p )
Old way of handling notification
In Swift we focus on writing all the APIs in strongly typed manner, then why not same with Notifications? Let’s see an example of default way of doing notification handling.
We write this same code again and again or we create a BaseViewController
and have these defined or maybe a UIViewController
extension. But all of these are still not efficient as you have to dig into notification.userInfo
dictionary to get relevant information.
Typed Notificaion
(Sorry, about the art being not so good. Tried to do my best. ;))
We want to define notifications in such a way, where we can definitively get the data from our notification observer (strongly typed), not a userInfo dictionary. This way we will enforce swift type system to help us writing type safe and bug free code. In this process we will also redefine how we observe our notification to make our code DRY
(don’t repeat yourself).
To create typed notification we can first define an NotificationDescriptor
struct. Our NotificationDescriptor
will have two properties,
name
defining unique notification nameconvert
closure, which help us extract out data from Notification.userInfo
With help of Swift’s Generic type we can use above Struct for all type of notifications and describe our notifications using this.
Next we can extend NotificationCenter
to provide us a convenience method over default addObserver
method.
But there is one thing missing in above implementation. We have added the observer but we are ignoring the token received from addObserver
method. Without this token we won’t be able to deregister the notification. For this purpose we can define a Token
class.
And redefine our addObserver
method this way:-
We can store the Token
returned by above function as a ViewController property, when ViewController’s deinit
gets called, Token
will also gets destroyed and notification gets deregistered.
How to use it
We will define KeyboardShow and KeyboardHide notification using our NotificationDescriptor
.
Let’s define a struct with info we require from keyboard notification using KeyboardNotificationKeys.
We can also define an initializer to our KeyboardData
which take notification and instantiate KeyboardData
. This can be used as our convert function and we don’t have to redefine convert for KeyboardShow and KeyboardHide.
This is also the most important part of our Type-Safe Notification
. We will have strictly defined data in our application and all the parsing logic is separated out for easy debugging and testing.
KeboardShowDescriptor
and KeyboardHideDescriptor
will become
We have also encapsulated these properties in SystemNotification
struct, so that our global namespace doesn’t get polluted with all different types of notification descriptors.
UIViewController usage
Having different notification with respective descriptor defined at a central place, using these in a UIViewController is very simple and we don’t have to track the notification for deregister.
This way we are also freeing up our UIViewController from other logic and only allowing it to handle views. This is also highly reusable, all the repetitive code is moved to a single place and this makes our code DRY
.
For MVVM architecture above implementation fits perfect, a viewController should only handle view related logic only.
Inspiration
Above pattern is inspired from SwiftTalk Objc.io. I would highly recommend watching this episode. They also define a different pattern using Protocol for handling the Notification. But for our use case we are fine with above implementation, much simpler and easy to use.
Happy coding!
The moldedbits Team