Reputation: 105
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:
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?
Upvotes: 0
Views: 2187
Reputation: 105
Thanks to @arvidure and others, i managed to have the code below that works
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(dispatch:DispatchGroup, 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()
}
dispatch.notify(queue: .main, execute: {
print("number of categories : \(tabCategory.count)")
completed(tabCategory)
})
}
}
And this is how I call it in the viewcontroller
super.viewDidLoad()
let dispatch = DispatchGroup()
category=CategoryModelPicker()
//category.modelCategory=categoryData.getCategory()
//category.modelCategory=FirestoreService.getCategoryfromDB(completed: category?.modelCategory)
FirestoreService.getCategoryfromDB(dispatch:dispatch){(cat) in
dispatch.notify(queue: .main, execute: {
print("number of categories final: \(cat.count)")
self.category.modelCategory=cat
//Additional code
})
}
}
Thanks for the help :)
Upvotes: 2
Reputation: 3033
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)
})
}
Upvotes: 2
Reputation: 2328
It looks like you're running into issues from the asynchrony of your code.
Your function is calling return tabCategory
before your code contained within the brackets that actually gets your documents actually runs.
Use an escaping closure to call a function when your async process finishes.
Your finished product will look something like this:
static func getCategoryfromDB(completed: @escaping (([categoryModel]?, Error?)) -> Void) {
let rootCategory = FirestoreReferenceManager.rootEvents
rootCategory.getDocuments() { (querySnapshot, err) in
if let err = err {
tabCategory(nil, err)
} else {
var tabCategory=[categoryModel]()
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)")
}
gotData(tabCategory, nil)
}
}
}
Upvotes: 0