【问题标题】:Swift: How to fix infinite loop when adding a value to a Firebase variableSwift:如何在向 Firebase 变量添加值时修复无限循环
【发布时间】:2016-08-18 08:43:47
【问题描述】:

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

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 中的 score 变量确实会增加,但它不会停止运行。这会导致分数无限增加,这不是我想要的。我希望我的代码一次只在分数上加一个,但这似乎不起作用。任何人都可以帮助我找到我的无限循环,或者提出一种可以更有效地添加到 Firebase 中的分数变量的方法吗?

谢谢!

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

【问题讨论】:

    标签: swift firebase firebase-realtime-database


    【解决方案1】:

    Ivan 的回答将解决您当前遇到的问题。但是从服务器加载所有消息以检测用户点击了哪个消息听起来可能会浪费大量带宽。

    如果您要向用户显示来自 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)
      }
    }
    

    事务还可以解决您现在遇到的潜在竞争条件:如果两个用户几乎同时单击同一条消息,则其中一个用户可能会覆盖另一个用户的得分增量。

    【讨论】:

    • 我在currentData.value = currentData.value + 1 行的编辑器中遇到错误,说No '+' candidates produce the expected contextual result type 'AnyObject?'
    • 您可能需要像以前一样强制转换为 int:as! Int
    • 我试过currentData.value = currentData.value + 1 as! IntcurrentData.value as! Int = currentData.value + 1 但它不喜欢它。说operator '+' cannot be applied to operands of type 'AnyObject?' and 'Int' 类型错误一直让我很困惑!
    【解决方案2】:

    您已经设置了一个观察者,该观察者应该观察“消息”树及其所有子节点中的任何值变化。

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

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

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

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2019-03-30
      • 1970-01-01
      • 2016-02-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2023-03-19
      • 2020-05-07
      相关资源
      最近更新 更多