Swift 中的 Firebase 实时数据库
Posted
技术标签:
【中文标题】Swift 中的 Firebase 实时数据库【英文标题】:Firebase Realtime Database in Swift 【发布时间】:2018-07-26 19:57:04 【问题描述】:经过几个小时试图弄清楚发生了什么,却没有找到任何答案来填补我的空白,我终于决定在这里问一问。 虽然我认为我确实有并发问题,但我不知道如何解决它......
我有一个应用程序试图从 Firebase 实时数据库中提取具有以下内容的数据:
"products" :
"accessory" :
"foo1" :
"ean" : 8793462789134,
"name" : "Foo 1"
,
"foo2" :
"ean" : 8793462789135,
"name" : "Foo 2"
,
"cpu" :
"foo3" :
"ean" : 8793462789115,
"name" : "Foo 3"
,
"ios" :
"foo4" :
"ean" : 8793462789120,
"name" : "Foo 4"
,
"foo5" :
"ean" : 8793462789123,
"name" : "Foo 5"
我在 Product.swift 中有一个数据模型:
class Product
var identifier: String
var category: String
var ean: Int
var name: String
init(identifier: String, category: String, ean: Int, name: String)
self.init(identifier: identifier)
self.category = category
self.ean = ean
self.name = name
我想在另一个名为 FirebaseFactory.swift 的类中获取数据,我打算用它来与 Firebase 通信:
import Foundation
import FirebaseDatabase
class FirebaseFactory
var ref = Database.database().reference()
func getAvailableProducts() -> [Product]
var products = [Product]()
var data: DataSnapshot = DataSnapshot()
self.ref.child("products").queryOrderedByKey().observeSingleEvent(of: .value) (snapshot) in
data = snapshot
// 1st print statement
print("From within closure: \(data)")
// 2nd print statement
print("From outside the closure: \(data)")
// Getting the products yet to be implemented...
return products
现在我只是想从我的一个视图控制器中调用getAvailableProducts() -> [Product]
函数:
override func viewWillAppear(_ animated: Bool)
let products = FirebaseFactory().getAvailableProducts()
我现在的问题是第二次打印在第一次之前打印 - 这也意味着从快照中检索数据并将其分配给 data
变量不会发生。 (我知道创建我的 Product 对象的代码丢失了,但那部分实际上不是我的问题——并发是......)
任何提示 - 在我拔掉我的头发之前 - 非常感谢!
【问题讨论】:
【参考方案1】:您的理论走在了正确的轨道上:您所描述的行为是异步数据如何与闭包一起工作。您已经体验过这如何导致返回所需数据出现问题。这是一个很常见的问题。事实上,我最近为此写了一个blog,我建议您检查一下,以便您可以应用解决方案:将闭包合并到您的函数中。这是您展示的特定情况下的样子:
func getAvailableProducts(completion: @escaping ([Product])-> Void)
var products = [Product]()
var data: DataSnapshot = DataSnapshot()
self.ref.child("products").queryOrderedByKey().observeSingleEvent(of: .value) (snapshot) in
data = snapshot
// do whatever you were planning on doing to return your data into products... probably something like
/*
for snap in snapshot.children.allObjects as? [DataSnapshot]
let product = makeProduct(snap)
products.append(product)
*/
completion(products)
然后在viewWillAppear中:
override func viewWillAppear(_ animated: Bool)
FirebaseFactory().getAvailableProducts() productsArray in
// do something with your products
self.products = productsArray
// maybe reload data if you have a tableview
self.tableView.reloadData()
【讨论】:
太棒了,那是缺少的链接,非常感谢!我记得之前被完成关闭的东西绊倒了,我还不能把头绕过去。我想我仍然需要对这个主题做一些进一步的研究,但至少现在我的代码正在工作,我可以停止用头撞墙:-) Word,我花了一年多的时间才开始觉得我“了解”了整个闭包的事情!很高兴你可以停止撞头,大声笑 @asseeger 这是如何使用 Firebase 闭包的一个很好的例子。您可能已经知道这一点,但是经常让人们绊倒的事情是试图访问闭包之外的 self.products。该 var 仅在 FirebaseFactory().getAvailableProducts() 之后的 闭包内 有效。即,如果在 viewWillAppear 方法中添加了一个 print(self.products) ,紧跟在闭包的尾随“”之后,它将不会打印产品,因为该代码将在数据返回之前执行从 Firebase 关闭;代码比互联网快。【参考方案2】:如果我理解你的问题,你需要在事件发生后返回数据,因为是一个异步事件
class FirebaseFactory
var ref = Database.database().reference()
func getAvailableProducts() -> [Product]
var products = [Product]()
var data: DataSnapshot = DataSnapshot()
self.ref.child("products").queryOrderedByKey().observeSingleEvent(of: .value) (snapshot) in
data = snapshot
// 1st print statement
print("From within closure: \(data)")
// Process here the snapshot and insert the products in the array
return products
【讨论】:
我将无法从闭包中返回值,因为闭包本身是无效的。尝试这样做会导致Unexpected non-void return value in void function
error(对于闭包 n.b.)
你是对的,我的错... :(不过,Jen写了最完整的回复,看看吧!
我同意,得到了她的回答。无论如何感谢你的努力。 :-)
不。这不会真正起作用。如果您调用像 let myProducts = getAvailableProducts() 这样的函数,那么下一行是 print(myProducts),打印函数将在从 Firebase 填充产品之前被调用。 以上是关于Swift 中的 Firebase 实时数据库的主要内容,如果未能解决你的问题,请参考以下文章
如何在 Swift 中保存实时 Firebase 数据库中的数据?
在 Swift 中的 Firebase 实时数据库观察方法中具有异步函数的 DispatchGroup
在 Swift 中更新 Firebase 实时数据库中的父标题