Search code examples
iosswiftfirebasegoogle-cloud-firestoreread-data

How to return data in array from Firestore?


I am building an IOS app and I am at the stage where I want to load some categories in a pickerview. The list of categories is stored in Firestore as documents.

I have a function that does the following:

  1. Initiate an array
  2. Read data from Firestore
  3. Append the array with values
  4. Return the array

The problem is that the function seems to return the array without even getting any results from Firestore

My data model

class categoryModel {
    var catImg=""
    var catName=""
    var catID=""
    //set categories
    init(catImg: String, catName:String, catID:String){
        self.catName=catName
        self.catImg=catImg
        self.catID=catID
    }
}

Firestore reference

struct FirestoreReferenceManager {

    static let event = "events"

    static let db = Firestore.firestore()
    static let rootEvents = db.collection("events")
    static let rootUsers = db.collection("users")

}

Firestore service

class FirestoreService {

    static func getCategoryfromDB()->[categoryModel] {

        let rootCategory = FirestoreReferenceManager.rootEvents
        var tabCategory=[categoryModel]()


        rootCategory.getDocuments() { (querySnapshot, err) in
            if let err = err {
                print("Error getting documents: \(err)")
            } else {
                for document in querySnapshot!.documents {

                    tabCategory.append(categoryModel(catImg: document.data()["img"] as! String, catName:document.data()["name"] as! String, catID: document.documentID))

                    print("number of categories running: \(tabCategory.count)")
                }
            }

        }
        print("number of categories final: \(tabCategory.count)")
        return tabCategory
    }
}

Check what the log is showing

umber of categories final: 0
number of categories final: 0
number of categories running: 1
number of categories running: 2
number of categories running: 3
number of categories running: 4
number of categories running: 5
number of categories running: 6
number of categories running: 7
number of categories running: 8
number of categories running: 9
number of categories running: 10
number of categories running: 11
number of categories running: 1
number of categories running: 2
number of categories running: 3
number of categories running: 4
number of categories running: 5
number of categories running: 6
number of categories running: 7
number of categories running: 8
number of categories running: 9
number of categories running: 10
number of categories running: 11

The 2 first lines should actually be the lasts.

And when I read Firestore from a viewcontroller, the array is empty. I tried hardcoding the data model and it is working fine.

I read about some "delay" in getting data, but then how to fix this?

How do I solve the problem?


Solution

  • Something like this should do it. The dispatch is a group where you can add closures to. Once all of them are finished the notify closure is called, where you can return the data. Read up on dispatch groups, which will help.

    static func getCategoryfromDB(completed: @escaping ([categoryModel]) -> Void) {
    
            let rootCategory = FirestoreReferenceManager.rootEvents
            var tabCategory=[categoryModel]()
            let dispatch = DispatchGroup()
            dispatch.enter()
            rootCategory.getDocuments() { (querySnapshot, err) in
                if let err = err {
                    print("Error getting documents: \(err)")
                } else {
                    for document in querySnapshot!.documents {
    
                        tabCategory.append(categoryModel(catImg: document.data()["img"] as! String, catName:document.data()["name"] as! String, catID: document.documentID))
    
                        print("number of categories running: \(tabCategory.count)")
                    }
                }
                dispatch.leave()
    
            }
            dispatchGroup.notify(queue: .main, execute: {
                print("number of categories final: \(tabCategory.count)")
                completed(tabCategory)
    
            })
    
    
            }