I have the following problem, maybe there exists a solution. I need to call a given function with a completion handler in a loop from synchronous code. The problem is that the function calls might not complete in order, and I need to find a way to be able to know the order of the returned values.
func findNextWord(completionHandler: @escaping (String) -> Void) // Given
class A {
var words = [String]()
func retrieveAllWords() {
for _ in 0...20 {
findNextWord { [weak self] word in
self.words.append(word) // I want to be able to get the correct ordering in my array
}
}
}
What is the best way to do that? Thanks in advance.
Note: I tested a few things and I noticed that the closure displays variable a
with its value at the time the function was called. Maybe there is something to do with that.
import Foundation
class A {
let queue = DispatchQueue(label: "test")
var a = 0
func doInLoop() {
for _ in 0...5 {
doSomething()
}
}
func doSomething() {
a += 1
let a_not_self = a
print("outside a: \(a_not_self)")
orderPizza { [weak self] in
print("inside a: \(a_not_self)")
print("inside a (but self): \(self?.a)\n")
}
}
func orderPizza(completionHandler : @escaping () -> Void) {
queue.async {
sleep(5)
completionHandler()
}
}
}
var a = A()
a.doInLoop()
prints:
outside a: 1
outside a: 2
outside a: 3
outside a: 4
outside a: 5
outside a: 6
inside a: 1
inside a (but self): Optional(6)
inside a: 2
inside a (but self): Optional(6)
inside a: 3
inside a (but self): Optional(6)
inside a: 4
inside a (but self): Optional(6)
inside a: 5
inside a (but self): Optional(6)
inside a: 6
inside a (but self): Optional(6)
You could use a dictionary instead of an array (or both)
class A {
var words = [Int: String]()
func retrieveAllWords() {
for index in 0...20 {
findNextWord { [weak self] word in
self.words[index] = word
}
}
}