async가 아닌 걸 async로 바꾸는 걸 해봅시다
class CheckedContinuationBootcampManager {
func getData(url: URL) async throws -> Data {
do {
let (data, _) = try await URLSession.shared.data(from: url)
return data
} catch {
throw error
}
}
}
class CheckedContinuationBootcampViewModel: ObservableObject {
@Published var image: UIImage? = nil
let networkManager = CheckedContinuationBootcampManager()
func getImage() async {
guard let url = URL(string: "https://picsum.photos/300") else { return }
do {
let data = try await networkManager.getData(url: url)
if let image = UIImage(data: data) {
await MainActor.run(body: {
self.image = image
})
}
} catch {
print(error)
}
}
}
struct CheckedContinuationBootcamp: View {
@StateObject private var viewModel = CheckedContinuationBootcampViewModel()
var body: some View {
ZStack {
if let image = viewModel.image {
Image(uiImage: image)
.resizable()
.scaledToFit()
.frame(width: 200, height: 200)
}
}
.task {
await viewModel.getImage()
}
}
}
어떤 네트워크 매니저가 있고,
viewModel에서 다운로드 하는 로직을 처리하고 있었다고 해보자
async 하게 다운로드를 처리하고 있음!
지금 보면 URLSession.shared.data(from: )이 이미 async 메소드라 그냥 사용해주면 됐었죠
이번엔 completionHandler로 처리를 해볼건데
async가 최근에 나온거라 sdk같은 것들 사용하다 보면 저렇게 표현되어 있는 경우가 대부분일 거!
이럴 때 어떻게 async하게 바꿔줄 수 있을까?
func getData2(url: URL) async throws -> Data {
return try await withCheckedThrowingContinuation { continuation in
URLSession.shared.dataTask(with: url) { data, response, error in
if let data = data {
continuation.resume(returning: data)
}
}
}
}
continuation을 이용해서 만들어줘봤습니다
try await으로 잠시 멈춘 다음에 continuation안의 코드들이 실행되게 되고, continuation.resume이 되는 코드입니다!!
여기서 생각해볼 점은 data가 nil일 경우에는 continuation.resume이 실행되지 않는 다는 거?
그래서 이런 식으로 분기에 대한 처리들을 해줘야함!!
Check Continuation을 사용하면 async하지 않은 로직을 async하게 바꿔줄 수 있다!