0

I'm new to Swift. I'm trying to return an array with data from a firebase query; however, I think the closure is causing issues. I tried placing my return array on either side of the function, and using self. within the closure; however, no dice.

Below is my code:

//controls avatar collection view in the mainViewController
import Foundation
import Firebase

class AvatarModel{

//connect to firestore
let db=Firestore.firestore()

func getAvatars() -> [Avatar]{

    //set array to two dimensional string array...I tried putting this on both sides of the function using self. within the closure...
    var generatedAvatarArray=[Avatar]()

    //query firebase database
    db.collection("mainViewController").whereField("long", isGreaterThanOrEqualTo: -5).whereField("long", isLessThanOrEqualTo: 5).getDocuments() { (querySnapshot, err) in
        if let err = err {
            print("Error getting documents: \(err)")
        } else {
            for documents in querySnapshot!.documents {
                //parse JSON and prepare data to be added to array
                let JSON=documents.data()
                let avatar=Avatar()
                avatar.fileName=JSON["thumbImage"] as! String
                avatar.userName=JSON["partName"] as! String

                //add db data to array to be returned by function
                generatedAvatarArray.append(avatar)
            }
        }
        //print statement works.  Array is filled with db data from firestore.
        print("%%%\(generatedAvatarArray[0].userName)++++\(generatedAvatarArray[1].userName)")
    }
    //blank array here. no db data from firestore.
    return generatedAvatarArray
}
Jay
  • 34,438
  • 18
  • 52
  • 81
Matt M
  • 3
  • 3
  • Firebase is asynchronous and code is faster than the internet. What this means is the code *following* the closure will execute way before the code in the closure because it takes time for data to be retrieved from the Firebase server. What this means is you cannot return a value in this fashion. You should so something with your generatedAvatarArray within the closure, populate a tableViewdataSource and then reload it for example. See [this](https://stackoverflow.com/questions/43027817/how-to-perform-an-action-only-after-data-are-downloaded-from-firebase/43029121#43029121) answer. – Jay Dec 15 '19 at 15:15
  • Oh and see [this answer](https://stackoverflow.com/questions/53979516/how-to-setup-a-bar-button-with-a-value-of-firebase/53979561#53979561) from @Sh_Khan for how to work with completion handlers if you do need to work with the values obtained within a closure, outside of the firebase closure. – Jay Dec 15 '19 at 15:19

1 Answers1

0

The closure runs asynchronous. This means the method directly returns an empty 'generatedAvatarArray'.

You could try with a delegate pattern to pass the result inside of the closure to the calling method.

Stefan
  • 5,203
  • 8
  • 27
  • 51