비동기 함수를 하나만 사용할 때에는 그냥 completionHandler를 사용하면 되지만,
비동기 함수를 여러개 호출 후 가장 마지막에 끝나는 함수가 종료된 후에 completionHandler를 호출시킬 수 있다.
어떤 상황이냐면,

비동기 함수를 하나만 호출할 때는 completionHandler에 함수가 종료된 후 호출될 함수를 넣어주면 정상적으로 동작하지만,
여러개의 비동기 함수를 호출했을 때(for문을 써서 호출하는 등)의 상황을 보면 저런식일거다.

비동기함수는 먼저 호출한 함수가 먼저 종료된다는 보장도 되어있지 않고, for문을 이용해서 같은 함수를 보낸다면 어떤 한 함수에만 completionHandler를 넣어주는것도 이상하고 원하는 대로 작동한다는 보장도 되어있지 않을것이다.
그렇다고 모든함수에 completionHandler를 넣어주면 호출한 함수의 개수만큼 여러번 호출될것이다.
이럴때에는 DispatchGroup을 이용할 수 있다.
DispatchQueue를 통해서 비동기함수를 호출할 때는 직접 group에 넣어줄 수 있지만, 비동기적으로 작동하도록 이미 지정되어 group을 지정할 수 없는 함수들(firebase나 urlsession 등등)은 enter(), leave()함수를 이용할 수 있다. 후자만 설명하겠다.

사용법은 사진과 같은 구조로 이루어진다.
각 비동기 함수를 호출할 때에는 enter()를 호출해서 DispatchGroup에게 아직 모든 함수가 종료되지 않았음을 알린다.
그리고 각 비동기함수에 completionHandler가 있을것이므로 completionHandler에 leave()를 호출해서 자신의 함수가 끝났음을 알린다.
그러면 DispatchGroup은 모든 함수가 종료되었음을 알고 notify함수를 호출해 completionHandler와 같은 동작을 해줄 수 있다.
코드로 살펴보면,
|
1
2
3
4
5
6
7
8
9
10
11
12
|
let dispatchGroup = DispatchGroup()
for i in 0..<4 {
dispatchGroup.enter()
fetchPost(forPost: document.documentID) { post in
dispatchGroup.leave()
}
}
dispatchGroup.notify(queue: .main) {
print("모든 함수 종료되었을 때 호출할 함수")
}
|
|
|
|
|
|
|
|
cs |
DispatchGroup()으로 디스패치 그룹을 생성 후
fetchPost라는 비동기 함수가 호출되기 바로 직전에 enter()함수를 호출해 비동기 함수가 시작됨을 알린다.
그리고 각 비동기 함수가 종료되고 completionHandler가 실행될 때 leave()함수를 호출해서 비동기함수가 종료되었음을 알린다.
notify는 모든 비동기 함수가 종료되었을 때 호출되라고 예약하는 느낌으로 생각하면 될것같다.
그래서 모든 비동기 함수가 종료되면 예약을 걸어두었던 notify함수가 호출된다.
(+ 또한 notify에서 어떤 큐로 보낼지 정할 수 있다.)
'Swift' 카테고리의 다른 글
| keyPath의 함수기능 (0) | 2023.08.31 |
|---|---|
| 프로퍼티 감시자가 호출되는 경우 [Swift] (0) | 2023.08.20 |