Reputation: 1841
I need to call a specific Firebase reference and get back data. This operation will take place inside multiple VCs so I want to have a class where I will have various functions calling Firebase. For example, if I want to get all articles I will call my FirebaseHelpers class, and use the method/closure fetchArticles(). This way, if I want to refactor something I will only do it in FirebaseHelpers class, and not go through all VCs.
import UIKit
import Firebase
class FirebaseHelpers {
func fetchArticles(completion: @escaping ([Article]?, Error?) -> Void) {
var articles = [Article]()
let articlesQuery = Database.database().reference().child("articles").queryOrdered(byChild: "createdAt")
articlesQuery.observe(.value, with: { (snapshot) in
guard let articlesDictionaries = snapshot.value as? [String : Any] else { return }
articlesDictionaries.forEach({ (key, value) in
guard let articleDictionary = value as? [String: Any] else { return }
// build articles array
let article = Article(dictionary: articleDictionary)
print("this is article within closure \(article)")
articles.append(article)
})
})
completion(articles, nil)
}
}
let firebaseHelpers = FirebaseHelpers()
var articles = [Article]() {
didSet {
self.collectionView.reloadData()
}
}
// this is inside viewDidLoad()
firebaseHelpers.fetchArticles { (articles, error) in
guard let articles = articles else { return }
print("articles \(articles)")
self.articles = articles
}
The problem is that I don't get any results back. In my VC the print("articles (articles)") will return an empty array. But in my FirebaseHelpers fetchArticles() the print("this is article within closure (article)") will print the article(s) just fine.
Any idea why this is happening?
Thanks in advance.
Upvotes: 2
Views: 222
Reputation: 54516
You can move completion
inside your asynchronous function:
class FirebaseHelpers {
func fetchArticles(completion: @escaping ([Article]?, Error?) -> Void) {
var articles = [Article]()
let articlesQuery = Database.database().reference().child("articles").queryOrdered(byChild: "createdAt")
articlesQuery.observe(.value, with: { (snapshot) in
guard let articlesDictionaries = snapshot.value as? [String : Any] else { return }
articlesDictionaries.forEach({ (key, value) in
guard let articleDictionary = value as? [String: Any] else { return }
// build articles array
let article = Article(dictionary: articleDictionary)
print("this is article within closure \(article)")
articles.append(article)
})
completion(articles, nil) // <- move here
})
// completion(articles, nil) // <- remove
}
}
Otherwise completion
will be called before your asynchronous function.
Upvotes: 3