Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

In a loop, call a function having a completion handler, order the result

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.


Experimentations

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.

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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)

>Solution :

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
        }
    }
}
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading