Multicast Delegation in iOS instead of Notification Center

Ilker Baltaci
Dev Genius
Published in
4 min readJun 9, 2020

--

Broadcast towers Flickr

NotificationCenter is a typical example for the observer design pattern. It’s a “cool” and easy mechanism to broadcast information from one class to all registered listeners. You define a key for a notification, you add observers to this notification by its unique name. You implement in the observer class a handler function that is triggered upon receiving the notification. The sender broadcasts its information over the NotificationCenter which is responsible for keeping track of listeners and observers for the individual notifications.

Pros in theory

  • Loosely coupled design between interacting objects (Senders and Observers)
  • It archives a 1:M communication channel
  • New observers can be added without changing the sender or subject.
  • Observers can be added/removed at anytime.

NotificationCenter works pretty well but in terms of clean code and scalability that brings many fallbacks as the project size gets bigger

Problems that I have encountered

  1. Any object can send out a notification and any object can register itself for any notification as listener. It’s very difficult to debug or trace the flow of communication when a notification is sent out. When you see a notification in a new project for the first time. You probably search for its unique name to see all observers/senders and try to figure out how each sender pushes this notification as well how it’s handled on each listener side.
  2. Each notifications can send userInfo dictionary to pass additional information to its listeners. The same notification can be sent by with different userInfo dictionaries and I wish you all the best for getting the values via dictionary keys. That can even be a bigger headache when you work with multiple iOS developers in your team. :)
  3. When a notification is posted, the notification center iterates over the registered observers and invoke the corresponding handler functions on the thread that the notification is posted. Shortly if you post a notification on a background thread observers handlers will be also invoked on the SAME background thread. That’s fair enough but developers should keep an eye on the handlers which are invoked on a background thread that need to update the UI or vice versa when a handler is invoked on main thread that needs to make a heavy computation.

Multicast Delegation

Delegation is a powerful design pattern where one object acts on behalf of another object. In the traditional pattern, the delegating object keeps a reference to the other delegate object and sends a message to this objects over certain protocol methods. The protocol definition describes the common language between the delegating class and the delegate class in a structured way. This design patterns can be found nearly everywhere in a modern iOS App. (UITableViewDelegate, UITableViewDatasource, UIPickerViewDelegate)

In terms of communication the traditional delegation can be applied for any 1:1 communication since the delegating object holds a single delegate reference.

In multicast delegation approach, the delegating object can hold multiple delegate instances that conform to a certain protocol. Since the delegating class can notify multiple delegates at time, the communication channel is not limited with 1:1 and becomes 1:N just like in NotificationCenter. As the communication exchange occur in a structured way over the defined protocol methods, this approach eliminates the first 2 pitfalls of the NotificationCenter mentioned above.

The delegating objects need to store multiple delegate instances and they need to be held as weak references to avoid retain cycles. In my first multicast delegation attempt, I used the following approach to store delegate instances in a weak wrapper to break the strong reference holding of swift arrays.

How to store weak references in swift arrays.

Afterwards I found a much better and cleaner approach explained by Vadim Bulamin in his blog post about multicast delegate that uses NSHashTable to store the delegate objects.

Generic multicast delegate class with add, remove and invoke methods.
AuthenticationManager class that holds a multicastDelegate object with the type argument of AuthenticationManagerDelegate

As seen in line 15 all registered delegates will be invoked in case of logout and in line 21 all delegates will be invoked for login event.

To register and unregister as delegate to AuthenticationManager:

The compiler will complain if the listener does not implement the methods defined in AuthenticationManagerDelegate protocol. Since the multicastDelegate accesses its listeners over weak references, any deallocated listener will not be notifier by the invoke method. Due to that I only call remove method if the listener is not interested anymore for information provided by the multicast delegating object.

Conclusion

I personally only use NotificationCenter in my projects for iOS driven events like UIApplicationWillEnterForegroundNotification or UIKeyboardDidShowNotification.

As seen in the example above individual delegates can be added to delegating AuthenticationManager class during the whole life cycle of the app due to singleton nature of the delegating class. If the sender/observable is deallocated we would lose all registered delegates references and need reregister them when a new instance of the sender is initialized.

Having the need to have a singleton class for senders could be seen as pitfall of this approach. I will shortly write a new post to explain an extended version of this approach that would work with any type of sender class.

P.S: For projects targeting iOS versions by 13.0, it worths considering asynchronous event-processing framework Combine that was introduced by Apple in WWDC 19. Combine has huge range of applications and it will simplify the way developers deal with notifications, delegates and callbacks. It will be a new standard for reactive programming in iOS which has been done till then over third party frameworks.

--

--