Reputation: 1705
Assume a simple struct like this:
struct Foo {
let value: Int
let delay: TimeInterval
}
It has 2 functions, each taking a closure as a parameter. One is synchronously called, the other asynchronously after delay
:
extension Foo {
func sync(_ completion: (Int) -> Void) {
completion(value)
}
}
extension Foo {
func async(_ completion: @escaping (Int) -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + TimeInterval(delay)) {
completion(self.value)
}
}
}
Now assume I have an array of Foo
objects:
let foo1 = Foo(value: 1, delay: 1)
let foo2 = Foo(value: 2, delay: 0)
Now I want to query each of them to get the values they would supply and put those into an array. Synchronously, it can be done like this:
let syncValues = [foo1, foo2].reduce(into: []) { values, foo in foo.sync { values.append($0) } } // [1, 2]
Asynchronously, I want to do this and have foo2
report before foo1
does:
let asyncValues = [foo1, foo2].reduce(into: []) { values, foo in foo.async { values.append($0) } // [2, 1]}
However, I get an error when I try to do the asynchronous version:
Escaping closure captures 'inout' parameter 'values'
What is a good way to perform this asynchronous task?
Upvotes: 0
Views: 130
Reputation: 49590
Because it's async, you can't do this in a single synchronous statement. Assuming you understand that, using Combine would probably be easiest:
import Combine
let fooResultsPublishers = [foo1, foo2].publisher
.flatMap { foo in
Future { promise in
foo.async { promise(.success($0)) }
}
}
.collect()
To actually get the value, you need to use .sink
to act on it asynchronously:
fooResultsPublishers
.sink {
print($0) // [2,1]
}
// store it in long-living property, like
// var cancellables: Set<AnyCancellable> = []
.store(in: &cancellables)
Without Combine, you'd need to use something like a DispatchGroup
:
let group = DispatchGroup()
var values: [Int] = []
[foo1, foo2].forEach { foo in
group.enter()
foo.async { values.append($0); group.leave() }
}
group.notify(queue: .main) {
print(values) // [2,1]
}
Upvotes: 3