
💡url을 통해 이미지를 비동기로 다운하는 방법 3가지를 알아봅시다.
코드 구조는 다음과 같습니다.
struct **DownloadImageAsync: View → 뷰를 표현**class DownloadImageAsyncViewModel: ObservableObjectclass DownloadImageAsyncImageLoaderfunc handleResponse(data: Data?, response: URLResponse?) -> UIImage? 다운 받은 data를 image로 변환해줍니다.func handleResponse(data: Data?, response: URLResponse?) -> UIImage? {
guard
let data = data,
let image = UIImage(data: data),
let response = response as? HTTPURLResponse,
response.statusCode >= 200 && response.statusCode < 300 else {
return nil
}
return image
}func downloadWithEscaping(completionHandler: @escaping (_ image: UIImage?, _ error: Error?) -> Void) {
URLSession.shared.dataTask(with: url) { [weak self] data, response, error in
let image = self?.handleResponse(data: data, response: response)
completionHandler(image, error)
}
.resume()
}
func fetchImage() {
loader.downloadWithEscaping { [weak self] image, error in
DispatchQueue.main.async {
self?.image = image
}
}
loader.downloadWithEscaping "await" { [weak self] image, error infunc downloadWithCombine() -> AnyPublisher<UIImage?, Error> {
URLSession.shared.dataTaskPublisher(for: url)
.map(handleResponse)
.mapError({ $0 })
.eraseToAnyPublisher()
}
.dataTaskPublisher를 통해 combine을 사용할 수 있습니다..map(handleResponse)과 .mapError를 통해 data → UIImage? 와 URLError → Error 작업을 해줄 수 있습니다.func fetchImage() {
loader
.downloadWithCombine()
.receive(on: DispatchQueue.main)
.sink { _ in
} receiveValue: { [weak self] image in
self?.image = image
}
.store(in: &cancellables)
}
receiveValue를 통해 결과값인 image를 처리할 수 있습니다.func downloadWithAsync() async throws -> UIImage? {
do {
let (data, response) = try await URLSession.shared.data(from: url, delegate: nil)
return handleResponse(data: data, response: response)
} catch {
throw error
}
}
async 키워드를 입력해야 해당 함수들을 사용할 수 있습니다.URLSession.shared.data(from: delegate)가 비동기를 지원하는 함수입니다.async throws → UIImage?)이 completionHandler와 달리 명시되어 있어서 훨씬 직관적입니다.func fetchImage() async {
let image = try? await loader.downloadWithAsync()
await MainActor.run {
self.image = image
}
}
fetchImage() 함수도 이제 동시성을 사용하므로 async 키워드를 붙여 줍니다.dispatchQueue.main을 async에서는 사용 못하기 때문에 대신에 MainActor.run을 사용해 줍니다.Swiftful Thinking 강의
https://www.youtube.com/watch?v=p6q1RmYUsNU&list=PLwvDm4Vfkdphr2Dl4sY4rS9PLzPdyi8PM&index=1