简体   繁体   English

从Firebase数据库加载Swift Tableview数据

[英]Swift Tableview Load Data from Firebase Database

I am currently trying to display data from my real-time database of Firebase in different tableviews. 我目前正在尝试在不同的表格视图中显示Firebase实时数据库中的数据。

In my first tableview I load my first level of my database structure (this already works). 在我的第一个表格视图中,我加载了数据库结构的第一级(这已经起作用了)。

Now I want to see what the user selects in the first tableview, and then display the next level of my database in a new TableView. 现在,我想查看用户在第一个表格视图中选择的内容,然后在新的表格视图中显示数据库的下一层。

I have a function in my second TableViewController.swift file where to save in the selected row from the first TableView. 我的第二个TableViewController.swift文件中有一个函数,该函数保存在第一个TableView的选定行中。

This way I want to save the next level from my database into an array so that this data will be displayed in my second tableview. 这样,我想将数据库中的下一个级别保存到数组中,以便此数据将显示在第二个表视图中。 When I then debug my new array, I also see the correct data in the new array. 然后,当我调试新阵列时,我还会在新阵列中看到正确的数据。 However, the data is not displayed in the second TableView. 但是,数据不会显示在第二个TableView中。

I guess it's because the data is not 100% ready before the TableView loads. 我猜是因为在TableView加载之前数据还没有100%准备好。

Do you have a tip? 你有小费吗?

Firebase Structure: 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: 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: 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!
    }
}

UPDATE 1: Thanks to @Jay Lee for the above code. 更新1:感谢@Jay Lee提供了上面的代码。

UPDATE 2: 更新2: 在此处输入图片说明

You are not loading the data to the SecondTableViewController instance that is presented on your screen, but to a new SecondTableViewController instance that you created in the func tableView(_:=,cellForRowAt:) method in your FirstTableViewController . 你是不是将数据加载到SecondTableViewController被呈现在屏幕上的实例,而是一个新的SecondTableViewController您在创建的实例func tableView(_:=,cellForRowAt:)在你的方法FirstTableViewController The logs are printed from the multiple instances you created from it. 从您从中创建的多个实例中打印日志。

This is not what you want, as you are creating multiple SecondTableViewController instances every time a new cell shows in your FirstTableViewController . 这不是您想要的,因为每次在FirstTableViewController显示一个新单元格时,您都将创建多个SecondTableViewController实例。 You should rather get a reference to the actual SecondTableViewController that is presented and supply the data it. 您应该获得对所显示的实际SecondTableViewController的引用,并SecondTableViewController提供数据。

If you are using a storyboard, you can use prepare(for:sender:) to do that. 如果您使用的是故事板,则可以使用prepare(for:sender:)进行操作。 We have two choices: provide the entire data from the FirstTableViewController to SecondTableViewController using a delegate design pattern, or just provide value to SecondTableViewController and leave the fetching to it. 我们有两个选择:使用委托设计模式将所有数据从FirstTableViewControllerSecondTableViewController ,或者仅将value提供给SecondTableViewController并保留取回信息。 Based on your code, you can just supply the SecondTableViewController with value that your setIndex(value:) method in the SecondTableViewController uses, and get the data after the SecondTableViewController loads. 基于您的代码,你可以提供SecondTableViewControllervalue ,你的setIndex(value:)的方法SecondTableViewController使用,以及后得到的数据SecondTableViewController负荷。

For example, in your SecondTableViewController : 例如,在您的SecondTableViewController

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

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

and in your FirstTableViewController : 并在您的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]
    }
  }
}

But note that you already have a data to be shown on SecondTableViewController in your FirstTableViewController , so you should probably make a protocol and set FirstTableViewController its delegate. 但是请注意,您已经有一个数据要显示在SecondTableViewControllerFirstTableViewController ,因此您可能应该制定一个protocol并将FirstTableViewController设置为其委托。

EDIT: Your segue should not be connected like this: 编辑:您的segue不应该这样连接: 错误的segue but like this: 但是像这样: 正确的选择

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM