Home > Mobile >  Swift Async let with loop
Swift Async let with loop

Time:11-15

I want to get data in parallel. I found an example to call API in parallel but I want to store async let variables with loop.

Async let example. However, this example doesn't use a loop.

async let firstPhoto = downloadPhoto(named: photoNames[0])
async let secondPhoto = downloadPhoto(named: photoNames[1])
async let thirdPhoto = downloadPhoto(named: photoNames[2])

let photos = await [firstPhoto, secondPhoto, thirdPhoto]
show(photos)

I want to do something like the following.

let items = photoNames.map({ photo in
    async let item = downloadPhoto(named: photo)
    return item
}) 
let photos = await items
show(photos)

CodePudding user response:

let photos = await photoNames.map(downloadPhoto)
public extension Sequence {  
  func map<Transformed>(
    priority: TaskPriority? = nil,
    _ transform: @escaping (Element) async throws -> Transformed
  ) async rethrows -> [Transformed] {
    try await withThrowingTaskGroup(of: Transformed.self) { group in
      for element in self {
        group.addTask(priority: priority) {
          try await transform(element)
        }
      }
      
      return try await .init(group)
    }
  }
}
public extension Array {
  init<AsyncSequence: _Concurrency.AsyncSequence>(_ asyncSequence: AsyncSequence) async rethrows
  where AsyncSequence.Element == Element {
    self = try await asyncSequence.reduce(into: []) { $0.append($1) }
  }
}

CodePudding user response:

For looping thru an array and responding in parallel, you don't use async let. Your imaginary code...

let items = photoNames.map({ photo in
    async let item = downloadPhoto(named: photo)
    return item
}) 
let photos = await items
show(photos)

...needs simply to be converted to use a task group (typed directly in browser so be prepared to compensate as needed; note also that you have given insufficient info, as I do not know what type your are getting back from your downloadPhoto, so I have to wing it):

var result = [YourPhotoType]()
await withTaskGroup(of:YourPhotoType.self) { group in
    photoNames.forEach { name in
        group.addTask {
            async downloadPhoto(named: name)
        }
    }
    for await photo in group {
        result.append(photo)
    }
}

See my tutorial https://www.biteinteractive.com/swift-5-5-asynchronous-looping-with-async-await/ for more info (esp. on the problem that you've now lost the order of the original array).

  • Related