Press ESC to close

Swift What is Dispatch Group?

Hello friends, in this article, we will talk about what is Dispatch Group in Swift. Dispatch Group allows you to do multiple jobs asynchronously in your application. As an example, I will go through the library project in my Github repo. You can access the project here. The general work of the project is as follows.

He goes to Apple’s services and searches for the word entered by the user by dividing them into groups. There are different sections as movies, music, apps and books. Wherever the user wants to search, he searches in that section. When the user selects the music section, going to Apple’s services and searching the music section; When you select the book section, it searches the book section. Instead, when the user searches for something, let him search in all 4 sections. Accordingly, let’s show the loading icon on the screen. We will send 4 different service requests, but some will arrive earlier and some later, and the loading icon should remain on the screen until the last operation is completed.

I had an Interactor as below. It was re-searching each time the category changed.

import UIKit

protocol SearchInteractorOutputs: AnyObject {
    func onMoviesSearched(movies: MoviesModel?)
    func onNextPageFetched(movies: MoviesModel?)
    func onAllCategoriesSearched()
    func onError(error: BaseErrorModel)
}

final class SearchInteractor: BaseInteractor, Interactorable {
    weak var presenter: SearchInteractorOutputs?
    weak var entities: SearchEntities?
    
    func search(searchedText: String, type: SearchTypes) {
        services.searchMovie(searchedText: searchedText, type: type) { movies in
            self.presenter?.onMoviesSearched(movies: movies)
        } errorCompletion: { error in
            self.presenter?.onError(error: error)
        }
    }
    
    func search(searchedText: String, pageNumber: Int, type: SearchTypes) {
        services.searchMovie(searchedText: searchedText, page: pageNumber, type: type) { movies in
            self.presenter?.onNextPageFetched(movies: movies)
        } errorCompletion: { error in
            self.presenter?.onError(error: error)
        }
    }
}

In addition to this, I need to write a function to search all categories. Since I will send 4 different service requests, I am doing as follows. I am creating a Dispatch Group and before every service call make sure that this service is included in the Dispatch Group. Make sure to leave this group after the service process is finished. I include all 4 different service calls in this Dispatch Group and remove them after the process is finished. After all the processes included in this group are finished, I can do the remaining process with group.notify. If you are going to update the UI, make sure you do it in the main thread, but if you are going to request another service, you can do it globally.

import UIKit

protocol SearchInteractorOutputs: AnyObject {
    func onMoviesSearched(movies: MoviesModel?)
    func onNextPageFetched(movies: MoviesModel?)
    func onAllCategoriesSearched()
    func onError(error: BaseErrorModel)
}

final class SearchInteractor: BaseInteractor, Interactorable {
    weak var presenter: SearchInteractorOutputs?
    weak var entities: SearchEntities?
    
    func searchAllCategories(searchedText: String) {
        let group = DispatchGroup()
        
        group.enter()
        services.searchMovie(searchedText: searchedText, type: .movie) { movies in
            group.leave()
            self.presenter?.onMoviesSearched(movies: movies)
        } errorCompletion: { error in
            group.leave()
            self.presenter?.onError(error: error)
        }
        
        group.enter()
        services.searchMovie(searchedText: searchedText, type: .music) { movies in
            group.leave()
            self.presenter?.onMoviesSearched(movies: movies)
        } errorCompletion: { error in
            group.leave()
            self.presenter?.onError(error: error)
        }
        
        group.enter()
        services.searchMovie(searchedText: searchedText, type: .app) { movies in
            group.leave()
            self.presenter?.onMoviesSearched(movies: movies)
        } errorCompletion: { error in
            group.leave()
            self.presenter?.onError(error: error)
        }
        
        group.enter()
        services.searchMovie(searchedText: searchedText, type: .book) { movies in
            group.leave()
            self.presenter?.onMoviesSearched(movies: movies)
        } errorCompletion: { error in
            group.leave()
            self.presenter?.onError(error: error)
        }
        
        group.notify(queue: .main) {
            self.presenter?.onAllCategoriesSearched()
        }
    }
    
    func search(searchedText: String, type: SearchTypes) {
        services.searchMovie(searchedText: searchedText, type: type) { movies in
            self.presenter?.onMoviesSearched(movies: movies)
        } errorCompletion: { error in
            self.presenter?.onError(error: error)
        }
    }
    
    func search(searchedText: String, pageNumber: Int, type: SearchTypes) {
        services.searchMovie(searchedText: searchedText, page: pageNumber, type: type) { movies in
            self.presenter?.onNextPageFetched(movies: movies)
        } errorCompletion: { error in
            self.presenter?.onError(error: error)
        }
    }
}

If you have questions, you can reach us by sending an e-mail or comment.

Leave a Reply

Your email address will not be published. Required fields are marked *