Swift:如何在向Firebase变量添加值时修复无限循环

时间:2016-08-18 08:43:48

标签: swift firebase firebase-realtime-database

我的程序中有这段代码,应该允许用户点击消息,分数应该增加1:

super.collectionView(collectionView, didTapMessageBubbleAtIndexPath: indexPath)
        let data = self.messages[indexPath.row]

        print("They tapped: "  + (data.text) + "- " + (data.senderDisplayName))

        let rootRef : FIRDatabaseReference = FIRDatabase.database().reference()
        let senderID = FIRAuth.auth()!.currentUser!.uid

        rootRef.child("messages").observeEventType(.Value, withBlock: { (snap) in

            print(senderID)

            if snap.exists(){
                if let messagesDict = snap.value! as? [String : AnyObject]
                {
                    for each in messagesDict as [String : AnyObject]{

                        let postID = each.0
                        if let messageDict = each.1 as? [String:AnyObject]{
                            if senderID == messageDict["senderId"] as! String{

                                //Checking for the senderID of the user so that you only increment the score of that particular message post
                                var userScore = messageDict["score"] as! Int
                                userScore = userScore + 1
                                rootRef.child("messages").child(postID).child("score").setValue(userScore)

                                print(senderID)
                                print(messageDict["senderId"])
                                print(userScore)
                            }
                        }                   
                    }
                }
            }
        })

但是,当运行上述代码并且用户点击消息时,分数变量确实会在Firebase中增加,但它永远不会停止运行。这导致得分无限增加,这不是我想要的。我希望我的代码只需一次在分数中添加一个,但这似乎不起作用。是否有人能够帮助我找到我的无限循环或建议一种方法,我可以更有效地添加到Firebase中的得分变量?

谢谢!

P.S。我也知道这个函数本身不会多次运行,因为print语句:print("They tapped: " + (data.text) + "- " + (data.senderDisplayName))只打印一次,并返回正确的数据。

2 个答案:

答案 0 :(得分:3)

您已经设置了一个观察者,该观察者应该观察“messages”-tree及其所有子节点中的任何值更改。

这意味着每当您更新乐谱时,您也会在观察者中收到有关此内容的信息 - 您的代码将再次运行。要解决此问题,只有在您必须将观察者更改为仅获取一次更改时,才会设置您的分数:

rootRef.child("messages").observeSingleEventOfType(.Value, withBlock:

在此处阅读更多内容:https://firebase.google.com/docs/database/ios/retrieve-data

我还建议您查看数据库部分的结构:https://firebase.google.com/docs/database/ios/structure-data

答案 1 :(得分:3)

伊万的回答将解决您目前遇到的问题。但是,从服务器加载所有消息以检测用户点击的消息听起来像是一个潜在的浪费带宽。

如果您要显示从Firebase到用户的邮件列表,我建议您跟踪每封邮件的密钥。有了这些信息,您就不会扫描所有邮件,但可以直接查找被点击的邮件并通过交易增加其得分:

rootRef.child("messages").child(postID).child("score").runTransactionBlock({ (currentData: FIRMutableData) -> FIRTransactionResult in
  // Set value and report transaction success
  currentData.value = currentData.value + 1
  return FIRTransactionResult.successWithValue(currentData)
}) { (error, committed, snapshot) in
  if let error = error {
    print(error.localizedDescription)
  }
}

交易还将解决您现有的潜在竞争条件:如果两个用户几乎同时点击同一条消息,则可能会覆盖另一个用户的分数增量。