firebase 中的更改不刷新 table - 表不显示数组中的用户节点
Change in firebase doesn't refresh table - Tables not displaying user nodes from arrays
我正在尝试使用两个数组,用作两个 tableView 的数据源。一个数组包含用户类型:macro,另一个数组包含用户类型:micro.
如果用户类型从宏观变为微观(反之亦然),我想从一个 table 中删除用户并将其添加到另一个。
目前,如果在 Firebase 数据库中发生更改,我可以更新用户的标签,并在应用程序重新启动时将其显示在正确的数组中。 observe 函数只收集一次,如果它被更改,它不会更新 table 直到用户退出应用程序并重新打开它。我用于 observe.childChanged 的函数似乎不会立即更新用户应用程序上的数组,除非他们执行前面提到的操作。
我的主要问题是我的 table 没有向 table 显示用户。我可以访问他们的节点和用户,但他们没有出现在我的 tables.
中
这是我的用户的代码 class:
import UIKit
import Firebase
class User: NSObject {
var Name: String?
var Email: String?
var UID: String?
var Tag: String?
init?(from snapshot: DataSnapshot) {
let dictionary = snapshot.value as? [String: Any]
self.Name = dictionary!["Name"] as? String
self.Email = dictionary!["Email"] as? String
self.UID = dictionary!["UID"] as? String
self.Tag = dictionary!["Tag"] as? String
}
}
这是我用于加载和填充信息附加的 allUsersArray 的代码:
func loadAllUsersAndPopulateArray() {
let ref = Database.database().reference().child("Users")
ref.observeSingleEvent(of: .value, with: { snapshot in
let allUsersSnapshot = snapshot.children.allObjects as! [DataSnapshot]
for userSnap in allUsersSnapshot {
let user = User(from: userSnap)
self.allUsersArray.append(user!)
self.macroUsersArray = self.allUsersArray.filter { [=12=].Tag == "Macro" }
self.microUsersArray = self.allUsersArray.filter { [=12=].Tag == "Micro" }
self.observeChangeInUserProperty()
}
})
}
这是我观察来自 Firebase 的变化的代码:
func observeChangeInUserProperty() {
let ref = Database.database().reference().child("Users")
ref.observe(.childChanged, with: { snapshot in
let key = snapshot.key
let tag = snapshot.childSnapshot(forPath: "Tag").value as! String // ! = never optional
//get the user from the allUsersArray by its key
if let user = self.allUsersArray.first(where: { [=13=].Tag == key }) {
if user.Tag != tag { //if the tag changed, handle it
user.Tag = tag //update the allUsersArray
if tag == "Macro" { //if the new tag is Macro remove the user from the Micro array
if let userIndex = self.microUsersArray.firstIndex(where: { [=13=].Tag == key }) {
self.microUsersArray.remove(at: userIndex)
self.macroUsersArray.append(user) //add user to macro array
}
} else { //new type is micro so remove from macro array
if let userIndex = self.macroUsersArray.firstIndex(where: { [=13=].Tag == key }) {
self.macroUsersArray.remove(at: userIndex)
self.microUsersArray.append(user)
}
}
//reload the tableviews to reflect the changes
self.tableView.reloadData()
self.microTableView.reloadData()
}
}
})
}
这是我的控制器代码:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var allUsersArray = [User]()
var macroUsersArray = [User]()
var microUsersArray = [User]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
searchBar.delegate = self
tableView.register(UserCell.self, forCellReuseIdentifier: networkCell)
microTableView.delegate = self
microTableView.dataSource = self
microTableView.register(microCell.self, forCellReuseIdentifier: microCell)
loadAllUsersAndPopulateArray()
}
func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
if (tableView === self.tableView) {
return 1
}
else if (tableView === self.microTableView) {
// Do something else
return 1
}
fatalError("Invalid table")
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (tableView === self.tableView) {
let cell = tableView.dequeueReusableCell(withIdentifier: networkCell, for: indexPath) as! UserCell
let user = macroUsersArray[indexPath.row]
cell.textLabel?.text = user.Name
return cell
} else if (tableView === self.microTableView) {
let cell = tableView.dequeueReusableCell(withIdentifier: microCell, for: indexPath) as! microInfluencerCell
let user = microUsersArray[indexPath.row]
cell.textLabel?.text = user.Name
return cell
} else {
fatalError("Invalid table")
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (tableView === self.tableView) {
return macroUsersArray.count
}
else if (tableView === self.microTableView) {
return microUsersArray.count
}
else {
fatalError("Invalid table")
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if (tableView === self.tableView) {
return 72
}
else if (tableView === self.microTableView) {
return 72
}
else {
fatalError("Invalid table")
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if (tableView === self.tableView) {
dismiss(animated: true) {
let userName = self.macroUsersArray[indexPath.row]
self.showSecondViewController(user: userName)
print("Dismiss completed")
}
}
else if (tableView === self.microTableView) {
dismiss(animated: true) {
let userName = self.microUsersArray[indexPath.row]
self.showSecondController(user: userName)
print("Dismiss completed")
}
}
else {
fatalError("Invalid table")
}
}
}
func showSecondViewController(user: User) {
let SecondViewController = SecondViewController()
SecondViewController.user = user
let navigationController = UINavigationController(rootViewController: SecondViewController)
self.present(navigationController, animated: true, completion: nil)
}
func loadAllUsersAndPopulateArray() {
let ref = Database.database().reference().child("Users")
ref.observeSingleEvent(of: .value, with: { snapshot in
let allUsersSnapshot = snapshot.children.allObjects as! [DataSnapshot]
for userSnap in allUsersSnapshot {
let user = User(from: userSnap)
self.allUsersArray.append(user!)
self.macroUsersArray = self.allUsersArray.filter { [=14=].Tag == "Macro" }
self.microUsersArray = self.allUsersArray.filter { [=14=].Tag == "Micro" }
self.observeChangeInUserProperty()
}
})
}
func observeChangeInUserProperty() {
let ref = Database.database().reference().child("Users")
ref.observe(.childChanged, with: { snapshot in
let key = snapshot.key
let tag = snapshot.childSnapshot(forPath: "Tag").value as! String // ! = never optional
//get the user from the allUsersArray by its key
if let user = self.allUsersArray.first(where: { [=14=].Tag == key }) {
if user.Tag != tag { //if the tag changed, handle it
user.Tag = tag //update the allUsersArray
if tag == "Macro" { //if the new tag is Macro remove the user from the Micro array
if let userIndex = self.microUsersArray.firstIndex(where: { [=14=].Tag == key }) {
self.microUsersArray.remove(at: userIndex)
self.macroUsersArray.append(user) //add user to macro array
}
} else { //new type is micro so remove from macro array
if let userIndex = self.macroUsersArray.firstIndex(where: { [=14=].Tag == key }) {
self.macroUsersArray.remove(at: userIndex)
self.microUsersArray.append(user)
}
}
//reload the tableviews to reflect the changes
self.tableView.reloadData()
self.microTableView.reloadData()
}
}
})
}
}
我非常接近解决这个问题。任何帮助都会很棒。
编辑:
func loadAllUsersAndPopulateArray() {
let ref = Database.database().reference().child("Users").child("Talent")
ref.observeSingleEvent(of: .value, with: { snapshot in
let allUsersSnapshot = snapshot.children.allObjects as! [DataSnapshot]
for userSnap in allUsersSnapshot {
let user = User(from: userSnap)
self.allUsersArray.append(user!)
self.allUsersNames.append(user!.Name!)
}
self.observeChangeInUserProperty()
})
self.macroUsersArray = self.allUsersArray.filter { [=15=].Tag == "Macro" }
self.microUsersArray = self.allUsersArray.filter { [=15=].Tag == "Micro" }
self.tableView.reloadData()
self.microTableView.reloadData()
}
在 Jay 的帮助下,我找到了解决方案!
我需要在闭包中设置我的数组信息。每当一个人的标签更新时,应用程序需要关闭并重新打开以显示在 firebase 中所做的新更改。
谢谢@Jay 的帮助!!!
这里是新的功能代码:
func loadAllUsersAndPopulateArray() {
let ref = Database.database().reference().child("Users")
ref.observeSingleEvent(of: .value, with: { snapshot in
let allUsersSnapshot = snapshot.children.allObjects as! [DataSnapshot]
for userSnap in allUsersSnapshot {
let user = User(from: userSnap)
self.allUsersArray.append(user!)
self.allUsersNames.append(user!.Name!)
self.macroUsersArray = self.allUsersArray.filter { [=10=].Tag == "Macro" }
self.microUsersArray = self.allUsersArray.filter { [=10=].Tag == "Micro" }
self.tableView.reloadData()
self.microTableView.reloadData()
}
self.observeChangeInUserProperty()
})
您 运行 遇到的问题是 Firebase 是异步的 - firebase 数据仅在 Firebase 函数之后的闭包内有效。
闭包之后的代码将在闭包内的代码之前执行,因此您需要计划以异步方式处理该数据。
此外,由于您是用来自 firebase 的数据填充一个数组,而其他数组基于第一个,因此没有理由一遍又一遍地过滤它们;填充主数组,完成后填充其他数组。
最后,tableView 是敏感的,反复加载它们可能会导致闪烁。再次填充主数组,完成后填充其他数组,重新加载 tableViews - 一次。
这部分代码应该是这样的
func loadAllUsersAndPopulateArray() {
let ref = Database.database().reference().child("Users")
ref.observeSingleEvent(of: .value, with: { snapshot in
let allUsersSnapshot = snapshot.children.allObjects as! [DataSnapshot]
for userSnap in allUsersSnapshot {
let user = User(from: userSnap)
self.allUsersArray.append(user!)
self.allUsersNames.append(user!.Name!)
}
self.macroUsersArray = self.allUsersArray.filter { [=10=].Tag == "Macro" }
self.microUsersArray = self.allUsersArray.filter { [=10=].Tag == "Micro" }
self.tableView.reloadData()
self.microTableView.reloadData()
self.observeChangeInUserProperty()
})
}
我还建议删除 allUsersNames
数组,因为这些名称也存储在 allUsersArray
.
中
我正在尝试使用两个数组,用作两个 tableView 的数据源。一个数组包含用户类型:macro,另一个数组包含用户类型:micro.
如果用户类型从宏观变为微观(反之亦然),我想从一个 table 中删除用户并将其添加到另一个。
目前,如果在 Firebase 数据库中发生更改,我可以更新用户的标签,并在应用程序重新启动时将其显示在正确的数组中。 observe 函数只收集一次,如果它被更改,它不会更新 table 直到用户退出应用程序并重新打开它。我用于 observe.childChanged 的函数似乎不会立即更新用户应用程序上的数组,除非他们执行前面提到的操作。
我的主要问题是我的 table 没有向 table 显示用户。我可以访问他们的节点和用户,但他们没有出现在我的 tables.
中这是我的用户的代码 class:
import UIKit
import Firebase
class User: NSObject {
var Name: String?
var Email: String?
var UID: String?
var Tag: String?
init?(from snapshot: DataSnapshot) {
let dictionary = snapshot.value as? [String: Any]
self.Name = dictionary!["Name"] as? String
self.Email = dictionary!["Email"] as? String
self.UID = dictionary!["UID"] as? String
self.Tag = dictionary!["Tag"] as? String
}
}
这是我用于加载和填充信息附加的 allUsersArray 的代码:
func loadAllUsersAndPopulateArray() {
let ref = Database.database().reference().child("Users")
ref.observeSingleEvent(of: .value, with: { snapshot in
let allUsersSnapshot = snapshot.children.allObjects as! [DataSnapshot]
for userSnap in allUsersSnapshot {
let user = User(from: userSnap)
self.allUsersArray.append(user!)
self.macroUsersArray = self.allUsersArray.filter { [=12=].Tag == "Macro" }
self.microUsersArray = self.allUsersArray.filter { [=12=].Tag == "Micro" }
self.observeChangeInUserProperty()
}
})
}
这是我观察来自 Firebase 的变化的代码:
func observeChangeInUserProperty() {
let ref = Database.database().reference().child("Users")
ref.observe(.childChanged, with: { snapshot in
let key = snapshot.key
let tag = snapshot.childSnapshot(forPath: "Tag").value as! String // ! = never optional
//get the user from the allUsersArray by its key
if let user = self.allUsersArray.first(where: { [=13=].Tag == key }) {
if user.Tag != tag { //if the tag changed, handle it
user.Tag = tag //update the allUsersArray
if tag == "Macro" { //if the new tag is Macro remove the user from the Micro array
if let userIndex = self.microUsersArray.firstIndex(where: { [=13=].Tag == key }) {
self.microUsersArray.remove(at: userIndex)
self.macroUsersArray.append(user) //add user to macro array
}
} else { //new type is micro so remove from macro array
if let userIndex = self.macroUsersArray.firstIndex(where: { [=13=].Tag == key }) {
self.macroUsersArray.remove(at: userIndex)
self.microUsersArray.append(user)
}
}
//reload the tableviews to reflect the changes
self.tableView.reloadData()
self.microTableView.reloadData()
}
}
})
}
这是我的控制器代码:
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
var allUsersArray = [User]()
var macroUsersArray = [User]()
var microUsersArray = [User]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.delegate = self
tableView.dataSource = self
searchBar.delegate = self
tableView.register(UserCell.self, forCellReuseIdentifier: networkCell)
microTableView.delegate = self
microTableView.dataSource = self
microTableView.register(microCell.self, forCellReuseIdentifier: microCell)
loadAllUsersAndPopulateArray()
}
func numberOfSections(in tableView: UITableView) -> Int {
// #warning Incomplete implementation, return the number of sections
if (tableView === self.tableView) {
return 1
}
else if (tableView === self.microTableView) {
// Do something else
return 1
}
fatalError("Invalid table")
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if (tableView === self.tableView) {
let cell = tableView.dequeueReusableCell(withIdentifier: networkCell, for: indexPath) as! UserCell
let user = macroUsersArray[indexPath.row]
cell.textLabel?.text = user.Name
return cell
} else if (tableView === self.microTableView) {
let cell = tableView.dequeueReusableCell(withIdentifier: microCell, for: indexPath) as! microInfluencerCell
let user = microUsersArray[indexPath.row]
cell.textLabel?.text = user.Name
return cell
} else {
fatalError("Invalid table")
}
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
if (tableView === self.tableView) {
return macroUsersArray.count
}
else if (tableView === self.microTableView) {
return microUsersArray.count
}
else {
fatalError("Invalid table")
}
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if (tableView === self.tableView) {
return 72
}
else if (tableView === self.microTableView) {
return 72
}
else {
fatalError("Invalid table")
}
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if (tableView === self.tableView) {
dismiss(animated: true) {
let userName = self.macroUsersArray[indexPath.row]
self.showSecondViewController(user: userName)
print("Dismiss completed")
}
}
else if (tableView === self.microTableView) {
dismiss(animated: true) {
let userName = self.microUsersArray[indexPath.row]
self.showSecondController(user: userName)
print("Dismiss completed")
}
}
else {
fatalError("Invalid table")
}
}
}
func showSecondViewController(user: User) {
let SecondViewController = SecondViewController()
SecondViewController.user = user
let navigationController = UINavigationController(rootViewController: SecondViewController)
self.present(navigationController, animated: true, completion: nil)
}
func loadAllUsersAndPopulateArray() {
let ref = Database.database().reference().child("Users")
ref.observeSingleEvent(of: .value, with: { snapshot in
let allUsersSnapshot = snapshot.children.allObjects as! [DataSnapshot]
for userSnap in allUsersSnapshot {
let user = User(from: userSnap)
self.allUsersArray.append(user!)
self.macroUsersArray = self.allUsersArray.filter { [=14=].Tag == "Macro" }
self.microUsersArray = self.allUsersArray.filter { [=14=].Tag == "Micro" }
self.observeChangeInUserProperty()
}
})
}
func observeChangeInUserProperty() {
let ref = Database.database().reference().child("Users")
ref.observe(.childChanged, with: { snapshot in
let key = snapshot.key
let tag = snapshot.childSnapshot(forPath: "Tag").value as! String // ! = never optional
//get the user from the allUsersArray by its key
if let user = self.allUsersArray.first(where: { [=14=].Tag == key }) {
if user.Tag != tag { //if the tag changed, handle it
user.Tag = tag //update the allUsersArray
if tag == "Macro" { //if the new tag is Macro remove the user from the Micro array
if let userIndex = self.microUsersArray.firstIndex(where: { [=14=].Tag == key }) {
self.microUsersArray.remove(at: userIndex)
self.macroUsersArray.append(user) //add user to macro array
}
} else { //new type is micro so remove from macro array
if let userIndex = self.macroUsersArray.firstIndex(where: { [=14=].Tag == key }) {
self.macroUsersArray.remove(at: userIndex)
self.microUsersArray.append(user)
}
}
//reload the tableviews to reflect the changes
self.tableView.reloadData()
self.microTableView.reloadData()
}
}
})
}
}
我非常接近解决这个问题。任何帮助都会很棒。
编辑:
func loadAllUsersAndPopulateArray() {
let ref = Database.database().reference().child("Users").child("Talent")
ref.observeSingleEvent(of: .value, with: { snapshot in
let allUsersSnapshot = snapshot.children.allObjects as! [DataSnapshot]
for userSnap in allUsersSnapshot {
let user = User(from: userSnap)
self.allUsersArray.append(user!)
self.allUsersNames.append(user!.Name!)
}
self.observeChangeInUserProperty()
})
self.macroUsersArray = self.allUsersArray.filter { [=15=].Tag == "Macro" }
self.microUsersArray = self.allUsersArray.filter { [=15=].Tag == "Micro" }
self.tableView.reloadData()
self.microTableView.reloadData()
}
在 Jay 的帮助下,我找到了解决方案!
我需要在闭包中设置我的数组信息。每当一个人的标签更新时,应用程序需要关闭并重新打开以显示在 firebase 中所做的新更改。
谢谢@Jay 的帮助!!!
这里是新的功能代码:
func loadAllUsersAndPopulateArray() {
let ref = Database.database().reference().child("Users")
ref.observeSingleEvent(of: .value, with: { snapshot in
let allUsersSnapshot = snapshot.children.allObjects as! [DataSnapshot]
for userSnap in allUsersSnapshot {
let user = User(from: userSnap)
self.allUsersArray.append(user!)
self.allUsersNames.append(user!.Name!)
self.macroUsersArray = self.allUsersArray.filter { [=10=].Tag == "Macro" }
self.microUsersArray = self.allUsersArray.filter { [=10=].Tag == "Micro" }
self.tableView.reloadData()
self.microTableView.reloadData()
}
self.observeChangeInUserProperty()
})
您 运行 遇到的问题是 Firebase 是异步的 - firebase 数据仅在 Firebase 函数之后的闭包内有效。
闭包之后的代码将在闭包内的代码之前执行,因此您需要计划以异步方式处理该数据。
此外,由于您是用来自 firebase 的数据填充一个数组,而其他数组基于第一个,因此没有理由一遍又一遍地过滤它们;填充主数组,完成后填充其他数组。
最后,tableView 是敏感的,反复加载它们可能会导致闪烁。再次填充主数组,完成后填充其他数组,重新加载 tableViews - 一次。
这部分代码应该是这样的
func loadAllUsersAndPopulateArray() {
let ref = Database.database().reference().child("Users")
ref.observeSingleEvent(of: .value, with: { snapshot in
let allUsersSnapshot = snapshot.children.allObjects as! [DataSnapshot]
for userSnap in allUsersSnapshot {
let user = User(from: userSnap)
self.allUsersArray.append(user!)
self.allUsersNames.append(user!.Name!)
}
self.macroUsersArray = self.allUsersArray.filter { [=10=].Tag == "Macro" }
self.microUsersArray = self.allUsersArray.filter { [=10=].Tag == "Micro" }
self.tableView.reloadData()
self.microTableView.reloadData()
self.observeChangeInUserProperty()
})
}
我还建议删除 allUsersNames
数组,因为这些名称也存储在 allUsersArray
.