let mainQueue = DispatchQueue.main
let userInteractiveQueue = DispatchQueue.global(qos: .userInteractive)
올바른 비동기함수의 설계
리턴(return)이 아닌 콜백함수를 통해, 끝나는 시점을 알려줘야 한다.
❌ 이렇게 설계하면 안된다.
// 이렇게 return하도록 설계하면 안된다
func getImages(with urlString: String) -> UIImage? {
let url = URL(string: urlString)!
var photoImage: UIImage? = nil
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error {
print("에러있음: \(error)")
}
guard let imageData = data else { return }
photoImage = UIImage(data: imageData)
}.resume()
return photoImage
}
getImages(with: "https://bit.ly/32ps0DI") // 무조건 nil로 리턴함 ⭐️
URLSession.shared.dataTask
는 비동기적으로 작동하기 때문에 해당 작업이 끝나기 전에 return photoImage
이 실행 될 것이고 그러면 이미지를 리턴하는 것이 아니라 nil값을 리턴한다(해당 작업이 끝나지 전에 리턴하기 때문에)
✅ 올바른 함수(메서드)의 설계 - 콜백함수의 사용법
func properlyGetImages(with urlString: String, closure: @escaping (UIImage?) -> Void) {
let url = URL(string: urlString)!
var photoImage: UIImage? = nil
URLSession.shared.dataTask(with: url) { (data, response, error) in
if let error = error {
print("에러있음: \(error)")
}
guard let imageData = data else { return }
photoImage = UIImage(data: imageData)
closure(photoImage)
}.resume()
}
요약
비동기함수를 이어서 처리하는 것(코드상의 불편함) 해결 / Swift 5.5에서 도입
thanks to @Allen
Completion block이 어떤 의미를 가진건지 알 수 있었다. 하나의 operation이 끝난다고 해서 무조건적으로 completionblock이 바로 끝에 나오는 것이 아닐 수 있다. 다른 operation과 순서가 섞일 수 있기 때문에 operation의 일부 task 를 completion block에서 처리 하는 것을 하면 안된다는 것을 깨달았다!!
For문을 활용하여 여러개의 operation을 생성한 뒤 해당 작업을 queue에다 넣어주니 operation의 우선순위와 상관없이 동기적으로 작동하는 문제를 직면했다.
For문을 사용하는게 문제일까...
내일 부디 해결할 수 있기를...