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.