TaskGroup

Updated:

TaskGroup

If we have a whole bunch of asynchronous functions that we need to run like maybe 10 or 20. async let isn’t scalable how can we run a whole bunch a group of tasks at the same time concurrently.

Apple has actually given us something called a task group in which we can create a single group of tasks and run a whole bunch of tasks concurrently

  • Fetch multiple images without Task Group

You could image in that if the fetch images went to 10 or 20 or more. This is not very scalable

// MARK: -  DATA MANAGER
class TaskGroupBootCampDataManager {

func fetchImageWithAsyncLet() async throws -> [UIImage] {
  async let fetchIamge1 = fetchImage(urlString: "https://picsum.photos/300")
  async let fetchIamge2 = fetchImage(urlString: "https://picsum.photos/300")
  async let fetchIamge3 = fetchImage(urlString: "https://picsum.photos/300")
  async let fetchIamge4 = fetchImage(urlString: "https://picsum.photos/300")

  let (image1, image2, image3, image4) = await (try fetchIamge1, try fetchIamge2, try fetchIamge3, try fetchIamge4)
  return [image1, image2, image3, image4]
}

private func fetchImage(urlString: String) async throws -> UIImage {
  guard let url = URL(string: urlString)  else {
    throw URLError(.badURL)
  }
  do {
    let (data, _) = try await URLSession.shared.data(from: url, delegate: nil)
    if let image = UIImage(data: data) {
      return image
    } else {
      throw URLError(.badURL)
    }
  } catch  {
    throw error
  }
}
}

// MARK: -  VIEWMODEL
class TaskGroupBootCampViewModel: ObservableObject {
@Published var images: [UIImage] = []
let manager = TaskGroupBootCampDataManager()

func getImages() async {
if let images = try? await manager.fetchImageWithAsyncLet() {
self.images.append(contentsOf: images)
}
}
}

// MARK: -  VIEW
struct TaskGroupBootCamp: View {
// MARK: -  PROPERTY
@StateObject private var vm = TaskGroupBootCampViewModel()
let columns = [GridItem(.flexible()), GridItem(.flexible())]
// let url = URL(string: "https://picsum.photos/300")!
// MARK: -  BODY
var body: some View {
NavigationView {
ScrollView {
LazyVGrid(columns: columns) {
ForEach(vm.images, id: \.self) { image in
  Image(uiImage: image)
    .resizable()
    .scaledToFit()
    .frame(height: 150)
} //: LOOP
} //: GRID
} //: SCROLL
.navigationTitle("Task Group Practice")
.task {
await vm.getImages()
}
}
}

스크린샷

There’s got to be a better way to write and perform multiple concurrent asynchronous requests and the way we do that again is with the task group.

  • Fetch multiple images with Task Group
// MARK: -  DATA MANAGER
class TaskGroupBootCampDataManager {

func fetchImageWithAsyncLet() async throws -> [UIImage] {
async let fetchIamge1 = fetchImage(urlString: "https://picsum.photos/300")
async let fetchIamge2 = fetchImage(urlString: "https://picsum.photos/300")
async let fetchIamge3 = fetchImage(urlString: "https://picsum.photos/300")
async let fetchIamge4 = fetchImage(urlString: "https://picsum.photos/300")

let (image1, image2, image3, image4) = await (try fetchIamge1, try fetchIamge2, try fetchIamge3, try fetchIamge4)
return [image1, image2, image3, image4]
}

func fetchImageWithTaskGroup() async throws -> [UIImage] {
let urlStrings = [
  "https://picsum.photos/300",
  "https://picsum.photos/300",
  "https://picsum.photos/300",
  "https://picsum.photos/300",
  "https://picsum.photos/300",
]

return try await withThrowingTaskGroup(of: UIImage?.self) { group in
  var images: [UIImage] = []
  images.reserveCapacity(urlStrings.count)

  for urlString in urlStrings {
    group.addTask {
      try? await self.fetchImage(urlString: urlString)
    }
  }
  for try await image in group {
    if let image = image {
      images.append(image)
    }
  }
  return images
}
}

func fetchImage(urlString: String) async throws -> UIImage {
guard let url = URL(string: urlString)  else {
  throw URLError(.badURL)
}
do {
  let (data, _) = try await URLSession.shared.data(from: url, delegate: nil)
  if let image = UIImage(data: data) {
    return image
  } else {
    throw URLError(.badURL)
  }
} catch  {
  throw error
}
}
}

스크린샷


🗃 Reference

SwiftUI Thinking - https://youtu.be/epBbbysk5cU

Leave a comment