[英]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提供了上面的代码。
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. 我们有两个选择:使用委托设计模式将所有数据从FirstTableViewController
给SecondTableViewController
,或者仅将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. 基于您的代码,你可以提供SecondTableViewController
与value
,你的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. 但是请注意,您已经有一个数据要显示在SecondTableViewController
的FirstTableViewController
,因此您可能应该制定一个protocol
并将FirstTableViewController
设置为其委托。
EDIT: Your segue should not be connected like this: 编辑:您的segue不应该这样连接: but like this: 但是像这样:
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.