Chapter 3 challenge: an array instead of 4 async let?

I’ve attempted to solve Challenge 3, and initially tried using an array instead of four separate async let variables to avoid dependence on the exact number of parts. I experimented with the syntax but had no success, due to my lack of experience with this API. Can you help?

Below is the proposed solution for reference

let parts = (0..<total).map { partInfo(index: $0, of: total) }

async let part1 =
      downloadWithProgress(fileName: file.name, name: parts[0].name, size: parts[0].size, offset: parts[0].offset)
async let part2 =
      downloadWithProgress(fileName: file.name, name: parts[1].name, size: parts[1].size, offset: parts[1].offset)
async let part3 =
      downloadWithProgress(fileName: file.name, name: parts[2].name, size: parts[2].size, offset: parts[2].offset)
async let part4 =
      downloadWithProgress(fileName: file.name, name: parts[3].name, size: parts[3].size, offset: parts[3].offset)

return try await [part1, part2, part3, part4]
      .reduce(Data(), +)

Your solution seems to work at a quick glance. But if you want to be able to use an unknown number of downloads, you could try using withTaskGroup. I’m typing the code here without checking in Xcode, so please fix any typos.

let downloadParts = await withTaskGroup(of: Data.self) { group in
  for part in parts {
    group.addTask {
      return await downloadWithProgress(fileName: file.name, name: part.name, size: part.size, offset: part.offset)
    }
  }

  for await part in group {
    // work with your finished parts here
  }
}

Thank you! It turns out this is exactly what I hoped to find, and this topic is covered in detail in Chapter 7: Modern Concurrency in Swift, Chapter 7: Concurrent Code With TaskGroup | Kodeco

1 Like