How to use Async Let to perform concurrent methods in Swift | Swift Concurrency #5
async
에 따라 먼저 패치가 완료된 데이터부터 UI 적용 → 동시에 모든 패치된 데이터가 뜨도록 구현Task
한 개 사용Task
여러 개 사용Task
내부 async let
을 통해 여러 개의 데이터를 동시에 await
하기private func fetchImageAsyncLet() {
// Load fetched Data at the same time
Task {
do {
async let fetchImage1 = fetchImage()
async let fetchImage2 = fetchImage()
async let fetchImage3 = fetchImage()
async let fetchImage4 = fetchImage()
let (image1, image2, image3, image4) = try await (fetchImage1, fetchImage2, fetchImage3, fetchImage4)
let images = [image1, image2, image3, image4]
self.images.append(contentsOf: images)
} catch {
print(error.localizedDescription)
}
}
}
fetchImage
라는 비동기 함수를 통해 리턴async let
을 통해 await
를 할 때까지 대기 → 한 번에 (try) await
를 통해 데이터 패치를 완료 → 업데이트 동시에 수행import SwiftUI
struct AsyncLetBootCamp: View {
@State private var images: [UIImage] = []
@State private var navTitle = "AsyncLetBootCamp"
let columns = [GridItem(.flexible()), GridItem(.flexible())]
var body: some View {
NavigationView {
ScrollView {
LazyVGrid(columns: columns) {
ForEach(images, id: \.self) { image in
Image(uiImage: image)
.resizable()
.scaledToFit()
.frame(height: 120)
}
}
}
.navigationTitle(navTitle)
.onAppear {
fetchImageAsyncLet2()
}
}
}
private func getURL() -> URL? {
guard let url = URL(string: "https://picsum.photos/1000") else { return nil}
return url
}
private func fetchImage() async throws -> UIImage {
guard let url = getURL() else { throw URLError(.badURL) }
do {
let (data, _) = try await URLSession.shared.data(from: url)
guard let image = UIImage(data: data) else {
throw URLError(.badURL)
}
return image
} catch {
throw error
}
}
private func fetchImageSingleTask() {
Task {
let image = try await fetchImage()
self.images.append(image)
let image2 = try await fetchImage()
self.images.append(image2)
let image3 = try await fetchImage()
self.images.append(image3)
let image4 = try await fetchImage()
self.images.append(image4)
}
}
private func fetchImageMultipleTasks() {
Task {
let image = try await fetchImage()
self.images.append(image)
}
Task {
let image = try await fetchImage()
self.images.append(image)
}
Task {
let image = try await fetchImage()
self.images.append(image)
}
Task {
let image = try await fetchImage()
self.images.append(image)
}
}
private func fetchImageAsyncLet() {
// Load fetched Data at the same time
Task {
do {
async let fetchImage1 = fetchImage()
async let fetchImage2 = fetchImage()
async let fetchImage3 = fetchImage()
async let fetchImage4 = fetchImage()
let (image1, image2, image3, image4) = try await (fetchImage1, fetchImage2, fetchImage3, fetchImage4)
let images = [image1, image2, image3, image4]
self.images.append(contentsOf: images)
} catch {
print(error.localizedDescription)
}
}
}
private func fetchTitle() async -> String {
return "Fetched Title"
}
private func fetchImageAsyncLet2() {
Task {
do {
async let fetchImage1 = fetchImage()
async let fetchTitle = fetchTitle()
let (image, title) = await (try fetchImage1, fetchTitle)
self.images.append(image)
self.navTitle = title
} catch {
print(error.localizedDescription)
}
}
}
}
async let
을 통해 서로 다른 여러 개의 async
이미지를 동시에 처리 가능하지만, 개수가 여러 개 이상 증가한다면 taskGroup
을 사용할 필요가 있음try
를 하지 않는 경우는 throw
를 통해 에러를 던지지 않는 함수의 리턴값일 경우(`fetchTitle
은 asycn
하게 문자열을 리턴하는 함수이지만 에러를 throw
하지 않고 fetchImage1
는 에러를 throw
하기 때문에 fetchImageAsyncLet2
에서 fetchImage1
은 try
로 받음)Task
이미지 패치 과정 구현Task
이미지 패치 과정 구현Async let
을 통해 한 번에 데이터 패치 구현