1

I have a function where I make an asynchronous read call to Firebase to populate an array. The function returns without the call being finished. How can I wait for the asynchronous call to finish and then return the array? I have tried using dispatchQueue and semaphores though I cannot figure out how to solve this problem.

class func generateModelArray() -> [Model]{
    var dbref: DatabaseReference?
    dbref = Database.database().reference()
    var modelAry = [Model]()
    let semaphore = DispatchSemaphore(value: 1)
    dbref?.child("Parts").observe(.childAdded, with: { (snapshot) in
        semaphore.wait()
        let partName = snapshot.key
        let dict = snapshot.value! as? [String:AnyObject]
        let partYear = dict!["year"] as! String
        let partPrice = dict!["price"] as! String
        //print(partName, partYear, partPrice)
        let mod = Model(name: partName, year: partYear, price: partPrice)
        modelAry.append(mod)
        print(modelAry)
        semaphore.signal()
    })
    semaphore.wait()
    return modelAry
}

From my understanding of semaphores in linux, when I lock the semaphore, it will block the other thread, and when I Signal, it will unlock the semaphore and allow for the other thread to proceed. How can I lock the semaphore in the observe() call since the function will still return before the call starts?

cool guy
  • 13
  • 6

1 Answers1

0

With asynchronous calls you need to plan for your code to complete before execution of the async call is complete. Pass a completion handler closure into your function that you call with the results from Firebase. Something like this:

class func generateModelArray(complete: @escaping (_ result: Bool, _ error: Error?)->Void) -> [Model]{

Then when Firebase comes back you can just call your complete function:

var someResult = true
var someError = nil
complete(someResult, someError)

Adjust what the complete function accepts as arguments depending on what you want to return.

davidethell
  • 11,708
  • 6
  • 43
  • 63