Mobile app development: Using delegates and blocks in VIPER
When to use delegates and protocols for data requesting, and when do blocks do the trick in VIPER-based mobile development? Let's examine both instances in this tutorial!
In mobile development powered by VIPER architecture, we have multiple ways to request and get data from external sources. In this article, I’d like to discuss two options:
- delegates and protocols, perhaps the most natural one for VIPER,
- and blocks, even more interesting and efficient.
Differently than in MVC
, VIPER offers a different approach towards requesting and getting data. In my opinion, it's more secure. If you use the Generamba project to build your VIPER modules, you’re most probably used to delegates and protocols. It's common in VIPER, so let’s start with this one.
Delegates in VIPER
Requesting data in VIPER is very simple and secure. Let’s say we have View Controller in which we want to display some data right after it starts. VC informs Presenter that is ready to show data by the method viewIsReady()
. So then we call Interactor by some function, e.g. refreshData()
. Inteactor communicates with our Repository (it can be Core Data, JSON, XML - nevermind). Inside our Repository’s protocol, we create another one called dataDidChanged()
. It looks like this:
protocol MyRepositoryDelegate: class {
func dataDidChanged()
}
protocol MyRepository {
refreshData()
}
OK, that’s easy (peasy lemon squeezy :). When implementation of Repository fetches its data, it calls the dataDidChanged()
function. And this one is implemented in Interactor. Interactor informs Protocol (also by a delegate) that it needs to refresh data in View Controller. So it’s done.
Blocks in VIPER - a remedy for corner cases
However, in some corner cases refreshing may be not as simple as in the example above. Sometimes one Presenter can request data from many repositories. And if in every repository we have the same dataDidChanged()
method or if Interactor calls the same output method for every repository delegate, problems may arise.Flutter vs SwiftUI: A simple comparison
This is why we can use blocks.
Differently than delegates, blocks are focused on single tasks. You send a request and you wait till it’s done. So in our case, calling a request from Presenter would look like this:
func refreshData() {
interactor.refreshData{ (receivedData) in
view.reloadViews()
}
The Interactor method (same as in Repository) would be:
func refreshData(block: @escaping (([ReceivedObject]) -> Void)
This solution is better when you want to focus just on one tashttps://prograils.com/posts/switching-from-mvc-to-viperk. For example if you have many requests in the same View Controller and don’t want to block the whole thread for the sake of a single task - you can simply split them thanks to blocks.
Wrapping up
Which method should I use, you may ask. Out of two ways of requesting data from external sources in VIPER, which I have presented in this short article, none is better than the other. We have to keep in mind that both delegates/protocols and blocks serve different tasks. Each of them is very useful for their dedicated use cases. Have fun with them and enjoy using VIPER!