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 functionerror(对于闭包 n.b.) 你是对的,我的错... :(不过,Jen写了最完整的回复,看看吧! 我同意,得到了她的回答。无论如何感谢你的努力。 :-) 不。这不会真正起作用。如果您调用像 let myProducts = getAvailableProducts() 这样的函数,那么下一行是 print(myProducts),打印函数将在从 Firebase 填充产品之前被调用。

以上是关于Swift 中的 Firebase 实时数据库的主要内容,如果未能解决你的问题,请参考以下文章

如何在 Swift 中保存实时 Firebase 数据库中的数据?

在 Swift 中的 Firebase 实时数据库观察方法中具有异步函数的 DispatchGroup

在 Swift 中更新 Firebase 实时数据库中的父标题

Swift 和 Firebase 实时数据库:如何获取对象的数量?

如何更改 Firebase 实时数据库中子值的顺序

从firebase实时数据库IOS Swift中检索数据