Swift 从对象数组映射到异步函数数组并等待它们全部

Fog*_*ter 9 async-await swift

我刚刚更新到 Xcode 13.2.1,现在可以访问异步等待,并且我正在尝试找到可以从合并“转换”为异步等待的地方。

我想实现以下目标...

给定一个像...的类型

struct Person {
  let name: String

  func fetchAvatar(completion: @escaping (UIImage?) -> Void) {
    // fetch the image from the web and pass it into the completion.
  }
}
Run Code Online (Sandbox Code Playgroud)

我目前有这样的功能......

func fetchAllTheAvatars(people: [Person], completion: ([UIImage]) -> Void) {
  Publisher.MergeMany(
    people.map { person in
      Future<UIImage?, Never> { promise in
        person.fetchAvatar { promise(.success($0)) }
      }
    }
  )
  .compactMap { $0 }
  .collect()
  .sink { completion($0) }
  .store(in: &cancellables )
}
Run Code Online (Sandbox Code Playgroud)

现在......在我看来,这可能是转向使用 async wait 的一个很好的候选者,AsyncSequence也许......?!?但它不一定是理想的,我只是想了解如何使用它们。我习惯了async awaitJS 和 TS,这似乎有点不同。:D

我向我的 Person 添加了一个包装函数...

func fetchAvatar() async -> UIImage? {
  await withCheckedContinuation { continuation in
    fetchAvatar { image in
      continuation.resume(returning: image)
    }
  }
}
Run Code Online (Sandbox Code Playgroud)

但现在我陷入了如何更新我的fetchAllTheAvatars功能的困境。

func fetchAllTheAvatars(people: [Person]) async -> [UIImage] {
  people.map { ...???... }
}
Run Code Online (Sandbox Code Playgroud)

我在网上看到的所有地方似乎都在使用for await line in url.lines { ... },但我还没有 AsyncSequence。我需要以某种方式将我的非异步数组“转换”Person为AsyncSequenceof () -> Image?。

那可能吗?我的处理方式完全错误吗?

谢谢

Rob*_*Rob 11

标准模式是TaskGroup. 为各个图像添加任务,然后await循环添加for,map或者在本例中为reduce:

\n
func fetchAllTheAvatars(people: [Person]) async -> [Person.ID: UIImage] {\n    await withTaskGroup(of: (Person.ID, UIImage?).self) { group in\n        for person in people {\n            group.addTask { await (person.id, person.fetchAvatar()) }\n        }\n        \n        return await group.reduce(into: [:]) { dictionary, result in \n            if let image = result.1 {\n                dictionary[result.0] = image\n            }\n        }\n    }\n}\n
Run Code Online (Sandbox Code Playgroud)\n

请注意,由于顺序无法保证,并且您的某些Person可能不会返回图像,因此我的实现返回一个高效的、与顺序无关的结构(即字典)。

\n

不用说,上面假设您Person符合Identifiable:

\n
struct Person: Identifiable {\n    let id = UUID()\n    let name: String\n    \n    func fetchAvatar() async -> UIImage? { \xe2\x80\xa6 }\n}\n
Run Code Online (Sandbox Code Playgroud)\n