ios - TableView 在观察 .childAdded 时继续添加行,即使在 Firebase 中未添加子项也是如此

标签 ios firebase swift3 firebase-realtime-database

我有一个由以下 firebase 数据库填充的 UITableView:

"games" : {
    "user1" : {
      "game1" : {
        "currentGame" : "yes",
        "gameType" : "Solo",
        "opponent" : "Computer"
      }
    }
  }

我在 viewDidLoad 中加载所有游戏,用户可以在另一个 UIViewController 中创建新游戏,一旦用户这样做并导航回 UITableView 我想用新行更新表。我正在尝试使用以下代码来做到这一点:

var firstTimeLoad : Bool = true
override func viewDidLoad() {
    super.viewDidLoad()
    if let currentUserID = Auth.auth().currentUser?.uid {
        let gamesRef = 
        Database.database().reference().child("games").child(currentUserID) 

        gamesRef.observe(.childAdded, with: { (snapshot) in
            let game = snapshot
            self.games.append(game)
            self.tableView.reloadData()
        })
    }
}

override func viewWillAppear(_ animated: Bool) {
    super.viewWillAppear(animated)
    if firstTimeLoad {
        firstTimeLoad = false
    } else {
        if let currentUserID = Auth.auth().currentUser?.uid {
            let gamesRef = Database.database().reference().child("games").child(currentUserID)
            gamesRef.observe(.childAdded, with: { (snapshot) in
                self.games.append(snapshot)
                self.tableView.reloadData()
            })
        }
    }
}

假设数据库中有一个当前游戏,当 viewDidLoad 运行时,表格正确显示一行。但是,每当我导航到另一个 View 并返回时,viewDidAppear 都会运行,并且由于某种原因,重复的 game 似乎被附加到 games 甚至尽管没有添加子项。

单元格由 games 数组填充:

internal func tableView(_ tableView: UITableView, cellForRowAt indexPath: 
IndexPath) -> UITableViewCell {

    let cell = Bundle.main.loadNibNamed("GameTableViewCell", owner: 
    self, options: nil)?.first as! GameTableViewCell

    let game = games[indexPath.row]
    if let gameDict = game.value as? NSDictionary {
        cell.OpponentName.text = gameDict["opponent"] as? String
    }

    return cell
}

更新:

感谢大家的回答!看来我误解了 firebase .childAdded 是如何运作的,我感谢你所有试图帮助我的回答我认为对我的应用程序来说最简单的事情就是在每次出现 View 时提取所有数据。

最佳答案

据我所知,这里的问题是每次你按下 View Controller 并返回到前一个时,它都会创建一个新的观察者,你最终会同时运行许多观察者,这就是为什么您的数据似乎是重复的。

您需要做的是在您的 viewDidDisappear 方法中,将 removeAllObservers 添加到您的 gameRef 中,如下所示:

override func viewDidDisappear(_ animated: Bool) {
   super.viewDidDisappear(animated)

   guard let currentUserId = Auth.auth().currentUser?.uid else {
      return
   }

   let gamesRef = Database.database().reference().child("games").child(currentUserId)

   gamesRef.removeAllObservers()

}

我在这里看不到你所有的代码,所以我不确定发生了什么,但是在添加你的 child 添加观察者之前,你需要从你的数组中删除所有元素,就像这样:

games.removeAll()

实际上,根据最佳实践,您不应该在 ViewDidLoad 中调用您的方法,而应该在 viewWillAppear 方法中添加您的观察者。

我现在无法测试您的代码,但希望它能像那样工作! 如果没有,请告诉我:)

更新:

如果您想一开始加载所有数据,然后只提取即将到来的新数据,您可以结合使用 observeSingleEvent(of: .value) 和 observe(.childAdded) 观察器,如下所示:

var didFirstLoad = false

gamesRef.child(currentUserId).observe(.childAdded, with: { (snapshot) in

    if didFirstLoad {
       // add your object to the games array here
    }

}

gamesRef.child(currentUserId).observeSingleEvent(of: .value, with: { (snapshot) in

    // add the initial data to your games array here

    didFirstLoad = true
}

通过这样做,第一次加载数据时,不会调用 .childAdded,因为那时 didFirstLoad 将被设置为 false。它只会在 .observeSingleEvent 被调用后被调用,从本质上讲,它只被调用一次。

关于ios - TableView 在观察 .childAdded 时继续添加行,即使在 Firebase 中未添加子项也是如此,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/46210205/

相关文章:

ios - 从 [NSObject removeObserver :forKeyPath:]? 捕获异常是否安全

iphone - 如何以编程方式添加 UITabBarController(无 xib 文件或 Storyboard)

java - FirebaseApp.initializeApp(Context);安卓错误;

swift3 - Swift 3 UnsafePointer($0) 不再在 Xcode 8 beta 6 中编译

ios - 如何将 TableViewCell 值传递给 Swift 3.0 中的新 ViewController?

ios - Xcode 构建失败。 Xcode 在单击 mainStoryBoard 时崩溃

ios - 在 Objective C 中共享 wifi 配置

android - Firestore 持久性如何真正发挥作用?

ios - 一次在 Firebase 中填充 UITableView 一组单元格

swift - 关闭 View Controller 不停止异步任务