DispatchGroup
작업을 Group으로 묶어 관리할 수 있는 하나의 개체
DispatchGroup
Dispatch 그룹은 작업을 하나의 그룹으로 묶어서 동기화 시킬 수도 있고 completion hander를 정의하면 작업이 끝났을 때의 동작을 실행할 수 있습니다
그럼 아래 그림을 보면 DispatchGroup 사용목적을 쉽게 이해할 수 있습니다
사용방법은 아래와 같습니다
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
'🍎iOS프로그래밍 > 오늘의 공부' 카테고리의 다른 글
iOS - 디스패치큐 알아보기 - main, global(), private (0) | 2022.07.15 |
---|---|
iOS - DispatchQueue 알아보기 (0) | 2022.07.14 |
iOS - GCD(Grand Central Dispatch)알아보기 (0) | 2022.07.12 |
Swift - iOS앱 http 통신 허용하기 (0) | 2022.06.29 |
[Xcode]시뮬레이터 GPS 좌표 설정하기 (0) | 2022.05.11 |
댓글