2017-09-14 42 views
0

未添加的孩子我有得到由以下火力数据库填充一个UITableView观察甚至.childAdded:表视图将继续添加行,而当火力地堡

"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与一列正常运行表显示。但是,无论何时,当我导航到另一个视图并导航时,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 
} 

UPDATE

感谢大家的答案!这似乎是我误解了firebase .childAdded的功能,我非常感谢您的所有答案,试图帮助我,我认为对于我的应用程序来说,最简单的方法就是在每次显示视图时拉取所有数据。

+0

当你追加的自我。游戏数组,那么你必须检查self.games数组是否包含相同的对象。如果是,那么你应该避免追加,否则继续追加。然后执行tableview.reloadData()。 –

+0

但是,为什么.childAdded在没有添加孩子的情况下返回一些东西? – mikew

+0

我认为你已经在viewDIdLoad和viewWillAppear中编写了相同的逻辑,所以两者都将同时调用,并且即使响应对象相同,两个响应也会附加到同一个数组self.games中。 –

回答

1

从我所看到的,这里的问题是,每次你推视图控制器并返回到前一个,它创建一个新的观察者,你最终有许多观察者在同一时间运行,这是为什么你的数据看起来是重复的。

你需要做的是你的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() 

} 

我看不到你的一切都在这里代码,所以我不知道发生了什么,但在此之前将你的孩子加入观察者,你需要从你的阵列删除所有的元素,像这样:

games.removeAll() 

其实,以达到最佳效果,你不应该打电话给你的方法,你的viewDidLoad里面,但研究所你应该在viewWillAppear方法中添加你的观察者。

我现在无法测试您的代码,但希望它能像那样工作! 让我知道,如果它不:)

UPDATE:

如果您想先加载所有数据,然后拉只有即将到来的新的新的数据,你可以使用一个组合在observeSingleEvent的(作者:.value的),然后观察(.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被调用后调用,就其本质而言,它只被调用一次。

+0

我在ViewDidLoad中有一个观察者的原因是,最初所有的数据都会被加载到表中。每次用户在viewWillAppear中添加一个新游戏时,我都希望桌子更新。我想我可以每次都在viewWillAppear中获取数据,它只是需要每次获取所有数据。 – mikew

+0

哦,我明白了!我编辑了我的答案。那么在这种情况下,请尝试在添加观察者之前删除数组中的所有元素,并让我知道它是否工作:) – Alex

+0

另外,如果您想保留在第一次加载期间加载所有数据的好处,而不是调用两次观察员(一个在viewDidAppear,一个在viewDidLoad中),只需要添加一个if else语句的viewDidAppear观察者里面做检查,因为childAdded将每进行一次初步的孩子,再每一个新的孩子加入 – Alex

1

尝试下面的代码,无需检查布尔,避免使用布尔这里所有的异步方法,它创造了我一个问题,在我的聊天应用程序之间时,其数据库的增长

//Remove ref in didLoad 
//Remove datasource and delegate from your storyboard and assign it in code so tableView donates for data till your array don't contain any data 
//create a global ref 
let gamesRef = Database.database().reference() 

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

     self.games.removeAllObjects() 
     if let currentUserID = Auth.auth().currentUser?.uid { 
      gamesRef.child("games").child(currentUserID)observe(.childAdded, with: { (snapshot) in 
       self.games.append(snapshot) 
       self.tableView.dataSource = self 
       self.tableView.delegate = self 
       self.tableView.reloadData() 
     }) 
      gamesRef.removeAllObserver() //will remove ref in disappear itself 
      //or you can use this linen DidDisappear as per requirement 
     } 
     else{ 
      //Control if data not found 
      } 
     } 

//TableView Delegate 

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 

      if self.games.count == 0{ 
       let emptyLabel = UILabel(frame: CGRect(x: 0, y: 0, width: self.view.bounds.size.width, height: self.view.bounds.size.height)) 
       emptyLabel.text = "No Data found yet" 
       emptyLabel.textAlignment = .center 
       self.tableView.backgroundView = emptyLabel 
       self.tableView.separatorStyle = .none 
       return 0 
      } 
      else{ 
       return self.games.count 
      } 
     } 
+0

我不确定如果我正确理解这一点,但看起来.childAdded仍然会抽出所有数据,所以我确实没有提高效率,就像我只是拉着新的孩子一样,因为这不是如何.childAdded函数。那是对的吗? – mikew

+0

firebase实际上是实时更新,如果任何值的任何值有任何变化,它的处理程序在此处起作用此时您需要管理您的函数来处理实时更新,您需要将代码放在任何情况下类似的值不会再次追加,这可以使用比较器或者在处理程序执行之前清除数组。在你的代码按我检查你只是追加数组中的值不清除它这就是为什么也许多个相同的值一次又一次地追加 –

+0

只是删除所有元素之前观察员,因为我已经在我的答案中提到它将解决您的问题。如果你仍然面临一个问题,问我,我会解释清楚它给你。 –