Site icon Mobile App Development Services

Communication Design Patterns in iOS

iOS App Communication Design

Every iOS and macOS application has both loosely coupled and tightly coupled entities that need to communicate in order to complete a specific job. For communication, we have several options available suitable for different scenarios developers can face. In this article, we will go through all the available options and try to extract some of the best practices for the communication of different objects.

If we analyze Apple’s Foundation framework, we see that most communication has been implemented on KVO, Notifications, and some using a delegation pattern as well. As far as this article is concerned we will try to go through beyond Apple’s framework and discuss blocks and target-actions as well. Of course, there are some cases in which no particular pattern is suitable which lets developers choose any patterns according to their taste and comfort, but there are many cases that are clear cut for developers to choose a particular communication pattern.

Before starting, keep in mind that we will often use the terms “sender” and “recipient”, what we mean by these terms is best explained in examples: UITableView is the sender and its delegate is the recipient, a UIButton is a sender and whoever is handling the action on touch-up-inside, is the recipient.

First, we will have a look at each of the design patterns and will try to outline the difference between them and then we will see why Apple has decided to implement any pattern in that specific scenario.

Notifications:

Notifications are a very good tool for broadcasting your messages around the app between unrelated parts of your code. They can carry some data as well in userInfo property. By unrelated I mean those parts which are not tightly coupled to each other by any means. 

For example, I recently implemented a location manager which keeps looking for location change of a user, if there is any change then it posts a notification to any entity which is interested in location change of user.

Notifications are used for one-to-many communication and you cannot reply to a notification that is why it is one-way communication.

Delegation:

Delegation is one of the most commonly used patterns in Apple’s Foundation framework. It allows us to send information or notifying about certain events between two tightly coupled entities. In the Delegation pattern, the recipient and sender know each other whereas in Notifications the recipient doesn’t know the sender and vice versa.

Since the delegation can define arbitrary methods, so we can design and model the communication as we wish by defining as many methods as we want. Since the recipient can reply to the sender as well via returning some values or through completion blocks so delegation is two-way and one-to-one communication.

Everything comes with a price of side effects, so aside from these advantages, there is some danger of overusing the delegation pattern as well, if two entities are tightly bound to each other that they cannot work without each other then it’s not sufficient to use delegation for the communication of those entities. Delegation may lead to retaining cycle as well because both sender and recipient have reference to each other.

Blocks:

Blocks can often fulfill the requirements that we achieve from delegation and it requires lesser code than delegation. But clearly, despite some similarities, they have completely separate sets of requirements and advantages.

One thing for sure you cannot use blocks where you’ll have to keep the reference of the parent object. For Example: think about the selection of a cell in any table view.

Why has Apple implemented a delegation pattern in it when it could easily have used the selection handler block implemented for it? like: self.tableView.selectionHandler = (indexPath: IndexPath){     }

The problem is that self retains the table view and even after executing the block it will never release the memory hence resulting in a memory leak so it’s never a good choice if using a block in this scenario.

Blocks are a very good choice if one entity has to send back a response that is specific to a particular method call which eventually doesn’t make this communication flexible as the delegation but easy to read and understand for any other developer. Some very common uses of blocks are completion handlers, Error handlers, response parsers, etc.

KVO:

KVO (Key Value Observers) is a pattern concerned about notifying about the property changes and implemented in Foundation and many frameworks built on top of it.

KVO is a useful communication if you are interested in any specific property and want to perform some operation when that property’s value gets changed. But there are obviously some requirements.

The communication can be one-to-many as multiple subscribers can register for any single property change. The most modern example of KVO implementation is reactive programming including the most popular reactive programming library RxSwift and Combine framework (just recently launched by apple). Reactive programming works on data streams where subscribers register on properties that they want to get notified when changed. There’s been a strong debate of reactive programming can replace the delegation pattern due to the same requirements as both should know the sender and the lifespan of the sender. if one handles the memory leak part very well in KVO then the delegation pattern can be replaced by the KVO.

Target-Action:

Target-Action is a typical pattern used to send a message between UI events. It is supported by both UIControl (in iOS) and NSControl (in macOS). it builds a very loose coupling between the recipient and the sender. The recipient doesn’t need to know the sender neither the sender needs to know who are the recipients, in that case, the target will be nil.

When the sender fires the message, the action travels up the responder chain of the object until it finds any recipient which is subscribed and sends the message to the recipient.

Although the Target-Action seems to be the simplest way of communication, there is a limitation in Target-Action that you cannot send a custom payload in these messages. The most you can do is pass the Control responsible for the message but nothing more. In iOS it is optional but for macOS, the Control is passed by default the recipient method as an argument.

Making The Right Choice:

Based on the behavior and requirements and we have constructed a chart which shows the selection of communication pattern according to your scenario. Please note that it’s not the final answer regarding the selection of communication patterns, but in most cases, it will do your job perfectly.

Framework Examples:
Now let’s go through some examples of some of Apple’s frameworks and try to figure out why Apple has decided to implement any specific communication pattern in each of the scenarios.

Notifications:
Core Data uses Notifications to send events like any change in managed object context (NSManagedObjectContextObjectsDidChanfgeNotification). Since the event is sent by the managed objects so we cannot specify the sender and as it is not a UI event and can have multiple recipients interested in it since it requires the one-way communication channel so Notification seems to be the only feasible option for this Scenario.

Delegation:

UITableView has a variety of functions in its delegate from managing the accessory views to notifying about tapping on any particular cell. Let’s take tableView:didSelectRowAtIndexPath again as an example. We already discussed why it has not been implemented on Blocks pattern, now let’s figure out why Target-Action pattern has not been used for this. As we discussed Target-Action events cannot carry custom payloads with them and this method needs to pass on the indexPath property to tell its recipient that which cell has been tapped so Target-Action is definitely not a possibility. What about KVO?. As KVO only tells about the change in the value of any property so the recipient will also need to track which cell has been tapped till now and the situation becomes more ugly if tableView is expected to provide multiple selections as well.

So, from both the comparison and the chart delegation is the best fit to implement the tableView scenario as its UIEvent with custom payload, knows the sender not having multiple recipients and it’s not a direct method call

Blocks:

For Blocks, let’s take the example of NSURLSession.dataTaskWith(url: URL). What is the communication back from the API Loading method?, if we follow the chat, it’s not a UI event and knows the sender of it without having multiple recipients. Furthermore, if we look at the documentation of NSURLSession , it deallocates the session object after executing the queue operation so there is no retain cycle created by having a reference of self so final condition is fulfilled as it gets deallocated at the very right time so we directly end up on Blocs option for the URL Session scenario.

KVO:

NSOperationQueue uses KVO to notify about certain changes in its state properties like isFinished, isExecuting, isCancelled.When the state changes queue gets the KVO notification. Why does it get a KVO notification?

The recipient of the messages (the operation queue) clearly knows the sender (the operation) and controls its lifespan by retaining it. Furthermore, this use case only requires a one-way communication mechanism. When it comes to the question of if the operation queue is only interested in value changes in the operation, the answer is less clear. But we can at least say that what has to be communicated (the change of state) can be modeled as value changes. Since the state properties are useful to have beyond the operation queue’s need to be up to date about the operation’s status, using KVO is a logical choice in this scenario.

Target-Action:

A very straightforward example of Target-Action is buttons, as they are first of all UI events and they don’t need to send custom payloads except their own reference and nothing else required to inform the recipient that button has been tapped. so Target-Action is the best option for implementing event handling of UIButtons.

If the target is nil, then the event loops through the responder chain and finds no subscribers to notify.

Conclusion:

At first, it seems like there are way too many options available for communication but once we start digging the differences and requirements we end up on a specific pattern to correctly sort out our scenario. The above chart will be a good start to decide which pattern to use according to your scenario. But of course it’s not the answer to every question, there can still be scenarios which won’t fit according to the above chart. If you find any of them do tell us about it.

I hope the article helped you out. Thank you for the read.

Are you looking for a complete development solution for your enterprise? Learn about our iOS App Development Services.