I'm trying to fetch a detailed list of items through a multi step async call. First I fetch a list of identifiers, after which I fetch the details for each of these identifiers.
func fetchList() async -> [UUID] {
// some async network call here
await Task.sleep(2)
return [UUID(), UUID(), UUID()]
}
func fetchDetail(forUUID uuid: UUID) async -> String {
// some async network call here
await Task.sleep(1)
return "\(uuid.uuidString.reversed())"
}
Individually these function work fine, but I'm stuck when I want to try and use a .map
on the list.
Task {
let list = await fetchList()
let details = await list.map { fetchDetail(forUUID: $0) } // Does not work
}
I did find out about the withTaskGroup
function and I could of course append to an array of items asynchronously, but I was wondering if there is a better way to achieve this functionality.
CodePudding user response:
I believe you don't need to use 'await' in front of list.map, as the function you are calling already has 'await' in it. Plus, ".map" is synchronous.
CodePudding user response:
Map for async code needs AsyncSequence
to work on.
struct DelayedUUIDs: AsyncSequence {
typealias Element = UUID
struct DelayedIterator: AsyncIteratorProtocol {
private var internalIterator = [UUID(), UUID(), UUID()].makeIterator()
mutating func next() async -> UUID? {
await Task.sleep(1_000_000_000)
return internalIterator.next()
}
}
func makeAsyncIterator() -> DelayedIterator {
DelayedIterator()
}
}
func fetchList() async -> DelayedUUIDs {
// some async network call here
await Task.sleep(1)
return DelayedUUIDs()
}
func fetchDetail(forUUID uuid: UUID) async -> String {
// some async network call here
await Task.sleep(1)
return "ID: \(uuid.uuidString)"
}
Task {
let list = await fetchList()
let details = list.map({ id in await fetchDetail(forUUID: id) })
for await value in list {
print(Date())
print(value)
}
for await value in details {
print(Date())
print(value as String)
}
}