Introducing Swift Action Delegate pattern Part 1
Trying to improve the delegation pattern in the Swift and iOS ecosystem.
Delegation is one of the core pattern on which most iOS SDKs are based on. First of all UIKit. Being familiar with them is core to developing a proper iOS app.
Delegation is solving one of the hardest problem in software development: communication and sharing of information between objects. It’s a complex problem with different opinionated solutions.
I have experimented different solutions which try to solve this problem, but I still think plain delegation is the way to go. It’s simple and robust. Yeah, it’s not trendy like reactive programming 🤐, but it works 🤷.
The problem with delegation is that it’s not immediate. It takes a moment to understand. And when you get familiar with it, it still involves writing a new delegate protocol for every context in which you need it.
Delegates are being used for two main reasons:
- A generic object that can be customised in the point of use. Think about a UICollectionView. It depend upon DataSource delegate methods to get the information it has to display.
- An object which has to communicate with another object. Think about a ParentVC which has presented modally a ChildVC. After ChildVC has completed his goal, it has to communicate to ParentVC he wants to be dismissed.
Let’s say we have a ParentVC which at different moment in time has to present RedVC and BlueVC. They both have to be dismissed at some point in the future. Maybe because the user just want to go back or because the user has selected some value.
In a classic scenario both the RedVC and BlueVC have to define a protocol which ParentVC has to conform to. This way ParentVC will be able to receive some information and eventually dismiss the child VCs.
This generates boilerplate code (which a lot of developers hate very much). It will generate boilerplate in each child VCs files, because protocols need to be defined. It will generate boilerplate code in the ParentVC because it has to conform to two differnent protocols.
Here a practical example (which you can run inside a Playground).
To avoid creating every time a new protocol, which adds very little value, let’s explore another avenue. Why can’t we create just one ActionDelegate
protocol which is made for communication between objects? It would be enough to have a flexible way to pass context specific information and it should work everywhere.
The idea is very simple: an ActionDelegate
protocol which receives a generic Action
as parameter. The Action is any value conforming to the DelegateAction
protocol. This way every object who wants to use the ActionDelegate
pattern can define his own context specific actions.
protocol DelegateAction {}
protocol ActionDelegate: class {
func actionSender(_ sender: Any, didReceiveAction action: DelegateAction)
}
Here it follows the previous example, but adopting the ActionDelegate pattern.
The solution, in my opinion, is a (bit) simpler and more consistent delegation pattern. I think it could be a way to write a (bit) less boilerplate code, but especially to have a consistent and stable communication channel between objects.
There are questions that need to be answered. Like, is it a good idea to have a single method responsible to reply to messages from other objects? It’s something similar to prepareForSegue
(🙈🙉🙊).
I am interested in your opinion. Please comment or test/fork the gists in a Playgorund and let me know a better solution.
Since I published this article, I got some feedback on some concepts to be improved. So, I wrote a follow up article: Introducing Swift Action Delegate pattern Part 2.