swift DispatchGroup 과 DispatchSemaphore - 2
[*] for 문을 이용해서 비동기 함수를 호출했을때 문제상황과 해결법
문제
아래 print 함수는 fetchData 함수가 리턴되는 콜백함수를 호출하기 전에 호출되어서 "text: " 으로 출력된다.
// 지연 후에 Int를 String으로 변환하는 함수
func fetchData(_ data: Int, delay: Double, completionHandler: @escaping (String)->()) {
print("fetchData - 진입 ")
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
print("fetchData - data \(data) ")
completionHandler("\(data)")
}
print("fetchData - 종료 ")
}
var text = ""
for i in 0..<20 {
fetchData(i, delay: Double.random(in: 0...0.2)) {
text += "\($0) - "
}
}
print("text:", text)
해결 - 1
DispatchGroup 사용
for 문 안의 모든 fetchData 함수가 동시에 호출되기 때문에, 모든 콜백이 완료되고 group.leave()를 보낸 후 group.notify()가 실행된다.
그래서 이번에는 print 문에 값은 출력 된다.
3 - 7 - 16 - 8 - 1 - 0 - 6 - 14 - 10 - 13 - 4 - 11 - 18 - 9 - 19 - 5 - 12 - 2 - 17 - 15 -
문제가 있다면 출력값이 순서대로 출력된것이 아니라 무작위로 출력이 되었다는 점이다.
어떻게 해결할 수 있을까?
import Foundation
// 지연 후에 Int를 String으로 변환하는 함수
func fetchData(_ data: Int, delay: Double, completionHandler: @escaping (String)->()) {
print("fetchData - 진입 ")
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
print("fetchData - data \(data) ")
completionHandler("\(data)")
}
print("fetchData - 종료 ")
}
let group = DispatchGroup()
var text = ""
for i in 0..<20 {
group.enter()
fetchData(i, delay: Double.random(in: 0...0.2)) {
text += "\($0) - "
group.leave()
}
}
group.notify(queue: DispatchQueue.main) {
print(text)
exit(0)
}
해결 - 2
DispatchSemaphore 사용
각 fetchData 함수는 이전에 실행되었던 작업이 완료될 때까지 기다린다.
출력은 순서대로 출력이 되고 결과는 아래와 같다.
0 - 1 - 2 - 3 - 4 - 5 - 6 - 7 - 8 - 9 - 10 - 11 - 12 - 13 - 14 - 15 - 16 - 17 - 18 - 19 -
import Foundation
// 지연 후에 Int를 String으로 변환하는 함수
func fetchData(_ data: Int, delay: Double, completionHandler: @escaping (String)->()) {
print("fetchData - 진입 ")
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
print("fetchData - data \(data) ")
completionHandler("\(data)")
}
print("fetchData - 종료 ")
}
DispatchQueue.global().async {
let semaphore = DispatchSemaphore(value: 0)
var text = ""
for i in 0..<20 {
fetchData(i, delay: Double.random(in: 0...0.2)) {
text += "\($0) - "
semaphore.signal()
}
semaphore.wait()
}
print(text)
exit(0)
}
요약하자면, 비동기 기능을 동기화하기 위한 두 가지 도구가 있다.
모든 작업이 완료될 때까지 기다려야된다면 DispatchGroup을 사용하고, 함수를 호출하는 순서대로 완료하고 실행하려면 DispatchSemahpore 사용하면 된다.
참고
'아이폰 개발 > Swift' 카테고리의 다른 글
swift stackview 안에 view 동적으로 생성하기 (0) | 2021.10.05 |
---|---|
swift 함수형 프로그래밍 정리 (0) | 2021.09.28 |
swift DispatchGroup 과 DispatchSemaphore - 1 (0) | 2021.09.25 |
swift Date 날짜 달력 관련 클래스 정리 (0) | 2021.09.24 |
swift - 최상위 ViewController 구하기 (0) | 2021.08.10 |