본문 바로가기
🍎iOS프로그래밍/오늘의 공부

iOS - DispatchGroup알아보기

by 둥둥동동# 2022. 7. 13.
728x90

DispatchGroup

 

작업을 Group으로 묶어 관리할 수 있는 하나의 개체

 

DispatchGroup

 

Dispatch 그룹은 작업을 하나의 그룹으로 묶어서 동기화 시킬 수도 있고 completion hander를 정의하면 작업이 끝났을 때의 동작을 실행할 수 있습니다

 

 

 

그럼 아래 그림을 보면 DispatchGroup 사용목적을 쉽게 이해할 수 있습니다 

https://sujinnaljin.medium.com/ios-%EC%B0%A8%EA%B7%BC%EC%B0%A8%EA%B7%BC-%EC%8B%9C%EC%9E%91%ED%95%98%EB%8A%94-gcd-7-4d9dbe901835

 

 

사용방법은 아래와 같습니다

 

DispatchGroup생성하고 큐에 작업을 넣을 때 그룹을 지정하면 됩니다

//그룹 생성
let group1 = DispatchGroup()

//Task정의시 group 지정
DispatchQueue.global().async(group: group1) { // task }

 

 

서로 다른  큐에 넣을 때 도 동일한 그룹으로 묶을 수 있습니다

//utility우선순위를 갖는 global큐 객체 
DispatchQueue.global(qos: .utility).async(group: group1) { // task }

//default우선순위를 갖는 global큐 객체
DispatchQueue.global().async(group: group1) { // task }

 

 

completion handler는 notify메서드를 사용합니다.

notify가 실행되었다는것은 해당 group이 비어있다는 뜻입니다

//main queue 에서 notification block 을 실행한다 
group1.notify(queue: .main) {
  self?.myLabel.text = "Group1으로 묶인 모든 작업이 끝났습니다."
}

 

 

notify가아닌 wait()메서드로 해당 그룹이 끝날 때 까지 쓰레드를 block(대기)시킬 수 있습니다

//그룹 생성
let group1 = DispatchGroup()

DispatchQueue.global().async(group: group1) { // task }

//group1 task가 실행될 때 까지 현재 쓰레드 block
group1.wait()

group1.wait() 메서드를 실행시킨 쓰레드는 group1이 끝날 때 까지 block가 됩니다

따라서 절대 main쓰레드에서 wait()메서드가 실행되어서는 안됩니다. 

 

 

 

 

wait()메서드 때문에 쓰레드가 무한 대기하면 자원낭비 및 데드락 상황이 생길 수 있으니 timeout을 인자로 줄 수 있습니다

//60초간 대기
group1.wait(timeout:.now() + 60)

 

 

 

 

- 만약 그룹에 속한 Task에 비동기(async) 메서드가 포함되어 있다면?

 

쓰레드는 group의 마지막 함수가 끝나면 그룹의 모든 task 가 종료된것으로 인식합니다

아직 비동기 메서드가 아직 수행중이더라도 말이죠

이 문제를 해결하기 위해서 task reference count를 관리하는 enter() leave() 메서드가 있습니다

enter()메서드로 task카운트를 +1 증가시키고 leave()로 task 카운트를 -1 시킬 수 있습니다

따라서 task카운트가 0이 되면 정확한 종료시점을 예측할 수 있을 것입니다

 

대표적인 예로 화면에 애니메이션을 표현하거나 URLSession으로 네트워킹을 할 때 사용할 수 있습니다

UIView의 aimation메서드는 비동기적인 메서드이므로 현재 쓰레드가 아닌 다른 쓰레드에서 처리됩니다

따라서 animation메서드 실행 전 enter()로 task카운트를 증가시켜 group의 마지막 task가 종료되더라도 끝나지 않은 것으로 인식 시켜 줍니다

이후 animation이 끝나면 leave()메서드로 task 카운트를 감소시켜 0으로 만든 뒤 group의 task가 끝났다는 것을 알려줍니다

 

코드는 아래와 같습니다

super.viewDidAppear(true)
 
let animationGroup = DispatchGroup()
 
// enter
animationGroup.enter()
UIView.animate(withDuration: 1.5) {
    self.view1.backgroundColor = .lightGray
} completion: { _ in
 
    // leave
    animationGroup.leave()
}
 
// enter
animationGroup.enter()
UIView.animate(withDuration: 3) {
    self.view2.backgroundColor = .blure
} completion: { _ in
 
    // leave
    animationGroup.leave()
    
}
 
// notify
animationGroup.notify(queue: .main) {
    let alert = UIAlertController(title: "완료", message: "애니메이션 종료", preferredStyle: .alert)
    self.present(alert, animated: true, completion: nil)
}
cs

 

동작화면

 

enter() leaver()가 없을 때 

 

 

 

 

 

 

참고자료

 

https://developer.apple.com/documentation/dispatch/dispatchgroup

 

Apple Developer Documentation

 

developer.apple.com

 

https://sujinnaljin.medium.com/ios-%EC%B0%A8%EA%B7%BC%EC%B0%A8%EA%B7%BC-%EC%8B%9C%EC%9E%91%ED%95%98%EB%8A%94-gcd-7-4d9dbe901835

 

[iOS] 차근차근 시작하는 GCD — 7

Dispatch Group의 개념에 대해 알아봅시다

sujinnaljin.medium.com

 

https://sujinnaljin.medium.com/ios-%EC%B0%A8%EA%B7%BC%EC%B0%A8%EA%B7%BC-%EC%8B%9C%EC%9E%91%ED%95%98%EB%8A%94-gcd-8-37146743787f

 

[iOS] 차근차근 시작하는 GCD — 8

Dispatch Group에 비동기 작업이 포함된 task 를 보내는 방법을 알아봅시다

sujinnaljin.medium.com

 

728x90

댓글