import UIKit
import XCTest
struct Downloader
{
static func download(photoURLs: [URL]) async throws -> [UIImage] {
try await withThrowingTaskGroup(of: UIImage.self) { group in
var collected = [UIImage]()
for url in photoURLs {
group.addTask {
let (data, _) = try await URLSession.shared.data(from: url)
return UIImage(data: data)!
}
}
for try await value in group {
collected.append(value)
}
return collected
}
}
}
final class PhotosTests: XCTestCase
{
func testDownloader() async throws {
let images = try await Downloader.download(photoURLs: [
URL(string: "https://placekitten.com/200/300")!,
URL(string: "https://placekitten.com/g/200/300")!
])
XCTAssertNotNil(images[0])
XCTAssertNotNil(images[1])
XCTAssertEqual(images.count, 2)
}
}
通用 map/reduce 版本
import UIKit
import XCTest
struct MapReduce
{
static func mapReduce<T,U>(inputs: [T], process: @escaping (T) async throws -> U ) async throws -> [U] {
try await withThrowingTaskGroup(of: U.self) { group in
// map
for input in inputs {
group.addTask {
try await process(input)
}
}
// reduce
var collected = [U]()
for try await value in group {
collected.append(value)
}
return collected
}
}
}
final class PhotosTests: XCTestCase
{
func testDownloader() async throws {
let input = [
URL(string: "https://placekitten.com/200/300")!,
URL(string: "https://placekitten.com/g/200/300")!
]
let download: (URL) async throws -> UIImage = { url in
let (data, _) = try await URLSession.shared.data(from: url)
return UIImage(data: data)!
}
let images = try await MapReduce.mapReduce(inputs: input, process: download)
XCTAssertNotNil(images[0])
XCTAssertNotNil(images[1])
XCTAssertEqual(images.count, 2)
}
}