[iOS] DispatchGroup
5 min readAug 17, 2023
A group of tasks that you monitor as a single unit.
작업을 Queue에 보내게 되면 GCD가 스레드를 적절히 생성해서 분배해준다. 하지만 여러 스레드에 퍼진 작업들이 한번에 끝나는 시점은 알 수 없다.
이 문제를 해결할 때 DispatchGroup을 사용한다.
말로 들었을 땐 잘 모르겠지만, 네트워크 통신을 할 때 자주 발생하는 문제를 해결 할 수 있다.🦿
networkService.postDetectLanguage(query: text ?? "") { result in
switch result {
case .success(let code):
self.networkService.postTranslateLanguage(langCode: code, text: text ?? "") { result in
switch result {
case .success(let data):
self.translationTextview.text = data
case .failure(let error):
print(error.errorString)
}
}
case .failure(let error):
print(error.errorString)
}
}
- 코드를 보면
networkService.postDetectLanguage
네트워크 클로저 안에서networkService.postTranslateLanguage
를 한번 더 호출하고 있는 상태이다. - DispatchGroup을 이용하면 이러한 콜백지옥을 벗어날 수 있다.
DispatchGroup
let myGroup = DispatchGroup()
- 그룹 선언
func enter()
- 작업이 그룹에 들어감을 명시해준다.
- task reference count +1.
func leave()
- 작업이 그룹에서 나감을 명시해준다.
- task reference count -1
func notify(qos: DispatchQoS, flags: DispatchWorkItemFlags, queue: DispatchQueue, execute: () -> Void)
- 현재 그룹의 모든 작업 실행이 완료되면(enter: 0) execute 후행 클로저에서 모든 작업이 완료된 후 일시적으로 처리해야할 작업을 실행시킬 수 있다.
func callAllRecommendation() {
let group = DispatchGroup() // DispatchGroup 생성
// enter (Task + 1)
group.enter()
callRecommendation(id: 976573) { data in
self.list = data
group.leave() // leave (Task - 1)
}
// enter (Task + 1)
group.enter()
callRecommendation(id: 479718) { data in
self.secondList = data
group.leave() // leave (Task - 1)
}
// enter (Task + 1)
group.enter()
callRecommendation(id: 569094) { data in
self.thirdList = data
group.leave() // leave (Task - 1)
}
// enter (Task + 1)
group.enter()
callRecommendation(id: 565770) { data in
self.fourList = data
group.leave() // leave (Task - 1)
}
// Task == 0
group.notify(queue: .main) {
self.posterCollectionView.reloadData()
}
}
// 네트워킹
func callRecommendation(id: Int, compleationHandler: @escaping (Recommendation) -> Void) {
AF.request(url, method: .get).validate().responseDecodable(of: Recommendation.self) { response in
... 네트워킹
- Alamofire을 활용한 네트워킹 메서드는 비동기적 메서드임으로 현재 쓰레드가 아닌 다른 쓰레드에 각각 처리된다.
callAllRecommendation
메서드는callRecommendation
메서드를 4번 실행 시키고 있는데, 각각 callRecommendation은 실행되기 전 group.enter()을 통해 Task Count를 증가시키고 group.leave()로 이스케이핑 클로저에서 메서드가 끝날 때 Task Count를 감소 시키고 있다.- 즉, Task가 모두 실행되고 끝나는 시점 (Task == 0)에
notify
를 실행시켜 모든 데이터를 받아온 후 한번에 CollectionView를 reload 할 수 있었다.
간단하게 DispatchGroup와 DispatchSemaphore의 차이
DispatchGroup
- 작업에 추가된 모든 작업들이 한번에 끝나는 시점을 알 수 있다. (
notify
) - 작업의 순서는 알 수 없다. 그저 그룹 내의 모든 작업이 한번에 끝나는 시점을 알 수 있음
DispatchSemaphore
- 한번에 수행될 수 있는 작업의 수를 제한 할 수 있다.
- let semaphore = DispatchSemaphore(value: 3) ← 3개로 제한
- wait과, signal을 통해 Task의 순서를 정할 수 있는 거 같다.
DispatchSemaphore는 공부가 더 필요👹