swift - 如何从 Firebase 实时数据库检索数据?

标签 swift firebase firebase-realtime-database google-cloud-storage

我正在尝试从我的 Firebase 数据库中检索 Firebase 中的数据集并将其呈现在表格 View 上。要向前呈现它并能够查看我放入 Firebase 服务器中的数据

我尝试在 Stackoverflow 上使用多个问题,但似乎没有任何效果,并且日志错误似乎始终相同 Log Error


Firebase 树

Products {
    dfkjsv4qc22aWE:{
       name:"Apples",
       weight:"1 Bag",
       price:"$5.99",
       imageUrl:"https://firebasestorage.googleapis.com/v0/b/randomImageapp.BlahBlask2233"
    }

    se04Fws444:{
       name:"Flower",
       weight:"Bouquet",
       price:"$10.99",
       imageUrl:"https://firebasestorage.googleapis.com/v0/b/randomImageapp.BlahBlask2233"
    }
}

import UIKit
import Foundation
import Firebase
import FirebaseStorage
import FirebaseDatabase

class ProductListController: UIViewController {

    @IBOutlet weak var productListTableView: UITableView!

    var feeds = [ProductList]()
    var dbRef :DatabaseReference!
    var storage : Storage!

    var dbRef: DatabaseReference!
    var storage: StorageReference!

    fileprivate var products: [ProductList] = []
    {
        didSet
        {
            productListTableView.reloadData()
        }
    }

    override func viewWillAppear(_ animated: Bool) {
        super.viewWillAppear(animated)
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        productListTableView.dataSource = self
        productListTableView.delegate = self

        dbRef = Database.database().reference()
        storage = Storage.storage().reference()

        readProducts()
        printProducts()
    }

    var productsArrayDataSource = [ProductList]()

    func readProducts() {
        let productsRef = self.dbRef.child("products") //self.ref points to my firebase
         productsRef.observe(.childAdded, with: { snapshot in
            let aProduct = ProductList(withSnapshot: snapshot)
            self.feeds.append(aProduct)
        })
    }

    func printProducts() {
        for product in self.feeds {
            print(product.id!, product.name!)
    }
}

extension ProductListController: UITableViewDelegate, UITableViewDataSource {

    func numberOfSections(in tableView: UITableView) -> Int {
        return 1
    }
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return products.count
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "ProductListCell") as!
        ProductListCell

        let details = products[indexPath.row]
        cell.updateUI(with: details)

        return cell
    }
}

import Foundation
import UIKit
import Firebase
import FirebaseDatabase

class ProductList {
    var name: String
    var price: String
    var weight: String
    var imageUrl: String

    init(withSnapshot: DataSnapshot) {
    self.name = withSnapshot.childSnapshot(forPath: "name").value as? String ?? "No Name"
    self.price = withSnapshot.childSnapshot(forPath: "price").value as? String ?? "No Price"
    self.weight = withSnapshot.childSnapshot(forPath: "weight").value as? String ?? "No Weight"
    self.imageUrl = withSnapshot.childSnapshot(forPath: "imageUrl").value as? String ?? "No ImageUrl"
}

}


import UIKit
import SDWebImage
import Firebase

class ProductListCell: UITableViewCell {

    @IBOutlet weak var productImage: UIImageView!
    @IBOutlet weak var productName: UILabel!
    @IBOutlet weak var weight: UILabel!
    @IBOutlet weak var price: UILabel!

    func updateUI(with productList: ProductList) {
        productName.text = productList!.name
        price.text = productList!.price
        weight.text = productList!.weight
        productImage.text = productList!.imageUrl
    }

    override func layoutSubviews() {
        super.layoutSubviews()
    }
}

编辑:这是我迄今为止在错误中得到的结果 error 2看起来这更像是一个 Firebase 问题,而不是我的编码错误

最佳答案

让我看看能否让您朝着正确的方向前进。这个问题有几个部分,所以我将深入探讨 Firebase 部分。如果此后 tableView 未显示,则这是 tableView 委托(delegate)问题,但看起来您的代码没问题。

要解决的第一个问题是 Firebase 结构 - 嗯,不是结构,而是键。来自文档

If you create your own keys, they must be UTF-8 encoded, can be a maximum of 768 bytes, and cannot contain ., $, #, [, ], /, or ASCII control characters 0-31 or 127. You cannot use ASCII control characters in the values themselves, either.

所以你可以看到你的 key 中有非法字符。通常,最佳做法是允许 Firebase 使用 .childByAutoId() 创建 key .

查看 ProductList 类,它确实很好,但您可能还想跟踪 Firebase key 。因此,例如用户选择它,您就会知道它是哪个项目。所以我只是添加了一个关键属性

class ProductList {
    var key: String
    var name: String
    var price: String
    var weight: String
    var imageUrl: String

    init(withSnapshot: DataSnapshot) {
        self.key = withSnapshot.key
        self.name = withSnapshot.childSnapshot(forPath: "name").value as? String ?? "No Name"
        self.price = withSnapshot.childSnapshot(forPath: "price").value as? String ?? "No Price"
        self.weight = withSnapshot.childSnapshot(forPath: "weight").value as? String ?? "No Weight"
        self.imageUrl = withSnapshot.childSnapshot(forPath: "imageURL").value as? String ?? "No ImageUrl"
    }
}

正如评论中提到的,子节点名称区分大小写,因此我还更新了代码以读取 imageURL 节点(以匹配您的结构)而不是 imageUrl .

然后是一个类数组来存储产品(如代码所示)

var feeds = [ProductList]()

然后是实际读取节点并填充 feeds 数组的代码。

func readProducts() {
    let productsRef = self.ref.child("Products") //self.ref points to my firebase
    productsRef.observe(.childAdded, with: { snapshot in
        let aProduct = ProductList(withSnapshot: snapshot)
        self.feeds.append(aProduct)
    })
}

这里需要注意的是,我们正在使用observe.childAdded 进行阅读。 .childAdded 迭代每个子节点,最初一次一个,并且 .observe 在该节点上留下一个观察者,每当添加新子节点时,该观察者都会调用闭包中的代码。

然后在稍后的某个时间,我们想看看数组中有什么

func printProducts() {
    for product in self.feeds {
        print(product.key, product.name)
    }
}

然后是调用 printProducts 时的输出

dfkjsv4qc22aWE Apples
se04Fws444 Flower

我从这个答案的结构中删除了非法字符,但 .childByAutoId() 又是你的 friend 。它始终有效、始终唯一,并将 key 与其包含的数据分开。

最后一个想法是:我什么时候重新加载我的 tableView。有几个选项,但一个是使用 .observeSingleEvent by .value 读取数据一次,然后迭代代码中的子节点,填充数组(类似于问题中的内容),然后重新加载 tableView。

第二个选项是利用 .value 事件始终在其他事件(例如 .childAdded)之后最后触发。因此,您可以使用 childAdded 来填充数组,但也可以添加一个 .value 事件,该事件将在添加所有子节点后触发,然后重新加载 tableView。 SO 上有许多该过程的示例。哦,现在有一个

Run Code after all children are added

关于swift - 如何从 Firebase 实时数据库检索数据?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57863561/

相关文章:

ios - 如何在应用程序切换器/关闭器栏上方设置输入附件 View 的约束?

firebase - Firebase 的 Cloud Functions 被多次调用

swift - 类型 [SubscriptType] 不符合协议(protocol) StringLiteralConvertible 错误

firebase - 如何检查客户的联系人是否正在使用我的应用程序?

firebase - Flutter中创建文档后返回新创建的Document ID

android - Firebase 分发错误 : failed to upload distribution. 处理二进制文件的时间比预期的要长,请重试

java - 如何构建 Firebase 实时数据库?

javascript - Firebase 与 Web : Using user Id in reference causes error: Uncaught TypeError: Cannot read property 'on' of undefined

swift - Swifter 可以用于 tvOS 应用程序吗?

ios - 我可以在创建新的 PFObject 时指定一个 objectId 吗?