Swift Tableview 从 Firebase 数据库加载数据

Posted

技术标签:

【中文标题】Swift Tableview 从 Firebase 数据库加载数据【英文标题】:Swift Tableview Load Data from Firebase Database 【发布时间】:2019-07-27 08:39:36 【问题描述】:

我目前正在尝试在不同的表格视图中显示我的 Firebase 实时数据库中的数据。

在我的第一个 tableview 中,我加载了我的第一级数据库结构(这已经有效)。

现在我想看看用户在第一个 tableview 中选择了什么,然后在新的 TableView 中显示我的数据库的下一级。

我的第二个 TableViewController.swift 文件中有一个函数可以保存在第一个 TableView 的选定行中。

这样,我想将数据库中的下一个级别保存到一个数组中,以便这些数据将显示在我的第二个表视图中。然后,当我调试我的新数组时,我还会在新数组中看到正确的数据。但是,第二个 TableView 中并没有显示数据。

我猜这是因为在 TableView 加载之前数据还没有 100% 准备好。

你有小费吗?

Firebase 结构:

-sports
    -Bicycle
        -BMX
            -Bike 1
                -img: „bike1.png“
                -text: „bike 1“
            -Bike 2
                -img: „bike2.png“
                -text: „bike 1“
    -Car
        -Audi
            -Car 1
                -img: „car1.png“
                -text: „car 1“
            -Car 2
                -img: „car2.png“
                -text: „car 2“

FirstTableViewController:

import UIKit
import Firebase

class FirstTableViewController: UITableViewController 

    var categorie = [String]()

    func loadData() 
        var ref: DatabaseReference!
        ref = Database.database().reference()

        ref.child("sports").observeSingleEvent(of: .value, with:  snapshot in
            if let sports = snapshot.value as? [String: Any] 
                for (title, _) in sports 
                    self.categorie.append(title)
                    self.tableView.reloadData()
                
            
        )
    

    override func viewDidLoad() 
        loadData()
        super.viewDidLoad()
    

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return categorie.count
    

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "sportCell")
        cell?.textLabel?.text = categorie[indexPath.row]
        return cell!
    

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
        // Set the segue's identifier in the Storyboard
        performSegue(withIdentifier: "firstToSecond", sender: self)
    

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
        if segue.identifier == "firstToSecond" 
            guard let destination = segue.destination as? SecondTableViewController,
                let indexPath = tableView.indexPathForSelectedRow else  return 
            destination.detailedValue = categorie[indexPath.row]
        
    

SecondTableViewController:

import UIKit
import Firebase

class SecondTableViewController: UITableViewController 

    var detailedValue: String?
    var secondArray = [String]()

    func setIndex(value: String) 
        loadData(index: value)
    

    func loadData(index: String) 
        var ref: DatabaseReference!
        ref = Database.database().reference()

        if (index != "") 
            ref.child("sports").child(index).observeSingleEvent(of: .value, with:  snapshot in
                if let sports = snapshot.value as? [String: Any] 
                    for (title, _) in sports 
                        self.secondArray.append(title)
                        self.tableView.reloadData()
                    
                
            )
        
    

    override func viewDidLoad() 
        super.viewDidLoad()
        if let detailedValue = detailedValue 
            loadData(index: detailedValue)
        
    

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int 
        return secondArray.count
    

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell 
        let cell = tableView.dequeueReusableCell(withIdentifier: "sorteCell")
        cell?.textLabel?.text = secondArray[indexPath.row]
        return cell!
    

更新 1: 感谢@Jay Lee 提供上述代码。

更新 2:

【问题讨论】:

【参考方案1】:

您不是将数据加载到屏幕上显示的SecondTableViewController 实例,而是加载到您在FirstTableViewControllerfunc tableView(_:=,cellForRowAt:) 方法中创建的新SecondTableViewController 实例。 日志是从您创建的多个实例中打印出来的。

这不是您想要的,因为每次在您的 FirstTableViewController 中显示一个新单元格时,您都会创建多个 SecondTableViewController 实例。 您应该获得对所显示的实际 SecondTableViewController 的引用并提供数据。

如果您使用故事板,您可以使用prepare(for:sender:) 来执行此操作。 我们有两个选择:使用委托设计模式提供从FirstTableViewControllerSecondTableViewController 的全部数据,或者只提供valueSecondTableViewController 并将获取留给它。 根据您的代码,您可以在SecondTableViewController 中使用setIndex(value:) 方法提供SecondTableViewControllervalue,并在SecondTableViewController 加载后获取数据。

例如,在您的SecondTableViewController:

class SecondTableViewController: UITableViewController 
...
  var detailedValue: String?

  override func viewDidLoad() 
    super.viewDidLoad()
    if let detailedValue = detailedValue 
      setIndex(value: detailedValue)
    
  
...

在你的FirstTableViewController:

class FirstTableViewController: UITableViewController 
...
  override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
    // Set the segue's identifier in the Storyboard
    performSegue(withIdentifier: "yourIdentifier", sender: self)
  
...
  override func prepare(for segue: UIStoryboardSegue, sender: Any?) 
    if segue.identifier == "yourIdentifier" 
      guard let destination = segue.destination as? SecondTableViewController,
            let indexPath = tableView.indexPathForSelectedRow else  return 
      destination.detailedValue = categories[indexPath.row]
    
  

但请注意,您的FirstTableViewController 中已经有要在SecondTableViewController 上显示的数据,因此您可能应该创建一个protocol 并将FirstTableViewController 设置为它的代表。

编辑: 你的 segue 不应该像这样连接: 但像这样:

【讨论】:

首先非常感谢您的帮助。我现在已经在我的代码中插入了你的建议(见上文)如果我现在点击“FirstViewController”中的“Bicylce”,我实际上会被重定向并看到预期的“BMX”。但是现在我会被转发两次(见更新2中的上图)当我点击图1中的“自行车”时打开(图2)然后自动切换到(图3)。您能否在这里给我一个提示,我仍然做错了什么?非常非常感谢。 我怀疑您的 segue 是从表格视图单元格连接到 SecondTableViewController 的。如果是这种情况,您应该将 segue 从 FirstTableViewController 本身连接到 SecondTableViewController 天哪,你是我的救命稻草:P 效果很好。现在我终于可以继续了。也许我会再次与您联系:D 没问题!很高兴听到它有帮助。 :) 再次您好:P,我正在取得进展。然而,我现在发现了一个错误。我正在运行数据库顶层的单个子级并将它们添加到一个新数组中。然后当我打印我的数组时,顺序总是不同的。有时 ["Car", "Bicycle"] 也有 ["Bicycle", "Car"]。如何指定遵守订单?

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

从 AppDelegate Swift 4 更新 tableView 行

Swift 3:tableView 复制从 Firebase 加载的图像

如何使用 Swift 从 tableview 和 sqlite3 中删除

SWIFT:从定义 tableView 到 tableViewCell 的 ViewController 通信数据

无法从swift ios中的一段tableview中删除单元格

从 Firebase 中基本读取并使用结果加载 tableview (Swift)