为啥我的代码在完成块中运行两次

Posted

技术标签:

【中文标题】为啥我的代码在完成块中运行两次【英文标题】:Why does my code run twice in the completion block为什么我的代码在完成块中运行两次 【发布时间】:2017-03-30 04:17:15 【问题描述】:

我有一些连接到 firebase 的代码,当它到达代码的某个部分时,它会运行两次它也不会删除我的 waitAlertController 它导致我的代码崩溃,因为它运行了两次然后第二次没有值,因为它第一次运行时将其删除,这是我的代码

这是我添加等待视图控制器并启动完成方法的表格视图。

func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) 
    let alertController = UIAlertController(title: "Accept Bet", message: "Match the bet of " + amountBets[indexPath.row], preferredStyle: .alert)

    let okButton = UIAlertAction(title: "No", style: .default, handler:  (action) -> Void in
        print("Ok button tapped")
    )

    let yesButton = UIAlertAction(title: "Yes", style: .default, handler:  (action) -> Void in
        // let them know to wait a second or the bet won't go through
        var waitController = UIAlertController(title: "Please Wait", message: "Your bet is being processed", preferredStyle: .alert)

        self.present(waitController, animated: true, completion: nil)
        //take away the usersMoney
        self.takeAwayMoney(self.amountBets[indexPath.row],index: indexPath.row, completion:  (result: Bool?) in

            guard let boolResult = result else 
                return
            
            var getResult = ""
            print("You have taken away the users money")

                print("you made it this far almost there")
                //let delayInSeconds = 3.0 // 1
                //DispatchQueue.main.asyncAfter(deadline: .now() + delayInSeconds)  // 2
        )
        if (self.userHasMoney == true) 
        self.updateBet(indexPath.row, completion:  (result: Bool?) in

            guard let checkRes = result else 
                return
            


        )

        self.getOpoosingUserNames(self.userName, indexPath.row, completion:  (anothaResult: Bool?) in

            guard let value = anothaResult else 
                return print("didn't work")
            
                    //wait for the first view to load in case it uploads to fast
                    sleep(1)
                    self.dismiss(animated: true, completion: nil)
                    let successController = UIAlertController(title: "Success", message: "You have made a bet with " + self.opposingUserNames!, preferredStyle: .alert)
                    let okButt = UIAlertAction(title: "Ok", style: .default, handler: nil)
                    successController.addAction(okButt)
                    self.present(successController, animated: true, completion: nil)
                    //lastly delete the opposing UserName
                    self.amountBets.remove(at: indexPath.row)
                    self.tableView.reloadData()
                    print("Second")

        )
         else 
            //display a alert that lets the user know hes broke
            let brokeController = UIAlertController(title: "Failed", message: "Reason: You don't have enough money!", preferredStyle: .alert)
            let okButt = UIAlertAction(title: "Ok", style: .default, handler: nil)
            brokeController.addAction(okButt)
            self.present(brokeController, animated: true, completion: nil)
        

    return
    )

    alertController.addAction(okButton)
    alertController.addAction(yesButton)
    present(alertController, animated: true, completion: nil)

这是我的 takeMoneyAway 方法

func takeAwayMoney(_ howMuch: String, index: Int, completion: @escaping (Bool)-> ()) -> Void
        if let notMuch = Int(howMuch) 

            let userID = FIRAuth.auth()?.currentUser?.uid

            datRef.child("User").child(userID!).observeSingleEvent(of: .value, with:  (snapshot) in
                // Get user value
                let value = snapshot.value as? NSDictionary
                let money = value?["money"] as? String ?? ""

                //convert money to int
                if let conMoney = Int(money) 
                    var conMoreMoney = conMoney
                    if conMoreMoney < notMuch 
                        print(" You don't have enough money")
                        completion(false)
                        return
                     else 
                        conMoreMoney -= notMuch
                        let values = ["money": String(conMoreMoney)]

                        //update the users money
                        self.datRef.child("User").child(userID!).updateChildValues(values)
                        completion(true)
                        /*
                        self.updateBet(index, completion:  (result: Bool?) in
                            guard let checkResult = result else 
                                return print("Failed to get result")
                            
                            if checkResult == true 
                                completion(true)
                             else 
                                completion(false)
                            
                        )
 */

                    

                
                // ...
            )  (error) in
                print(error.localizedDescription)
            
        
    

我的最后一个方法是去我的数据库更新值并抓住他们下注的人。

 func updateBet(_ index: Int, completion: @escaping (_ something: Bool?) -> Void) 
        let userID = FIRAuth.auth()?.currentUser?.uid
        datRef.child("User").child(userID!).observeSingleEvent(of: .value, with:  (snapshot) in
            // Get user value
            let value = snapshot.value as? NSDictionary
            // ...


            self.datRef.child("Bets").observe(.childAdded, with:  snapshot in
                //
                // this is the unique identifier of the bet.  eg, -Kfx81GvUxoHpmmMwJ9P
                guard let dict = snapshot.value as? [String: AnyHashable] else 
                    print("failed to get dictionary from Bets.\(self.userName)")
                    return
                
                let values = ["OpposingUsername": self.userName,"Show": "no"]


                self.datRef.child("Bets").child(self.tieBetToUser[index]).updateChildValues(values)
                let checkTheCodeWentHere = "Success"
                // now get the opposing username which is just the Username registered to that specific bet

                self.datRef.child("Bets").child(self.tieBetToUser[index]).observeSingleEvent(of: .value, with:  snapshot in
                    let thisValue = snapshot.value as? NSDictionary
                    if let username = thisValue?["Username"] as? String 
                        self.opposingUserNames = username
                        completion(true)
                     else 
                        completion(false)
                    

                )

            )

        )  (error) in
            print(error.localizedDescription)
        


    

所以在 tableview 方法中有一段代码说 if checkRes == true 花括号中的所有代码都运行了两次我用断点检查了这个,有人能告诉我这是为什么吗?

【问题讨论】:

您能否发布单个会话中的控制台日志,显示您的 print 语句的输出? 它将显示所有打印语句大约 20 次,每个 @Fahim 我更新了我的 xcode 中的代码,现在它可以工作了。我猜你不能嵌套完成函数 哦,我在断点测试过,我不记得了,但我很确定它不是。我现在无法弄清楚的一件事是,如果其中一个完成函数返回 false,我需要发生一些不同的事情。例如,我的第一个功能从用户那里拿走了钱。因此,如果用户没有钱,则该函数将返回 false,但函数仍将在其下方运行。我什至尝试设置一个布尔值,然后检查该布尔值是否为假,如果是则不要运行其他完成块@Fahim 通常,如果闭包中的动作有两个不同的结果,最简单的方法是传递两个闭包 - 一个代表成功,一个代表失败。然后根据闭包中发生的情况,调用成功块或失败块。 【参考方案1】:

无法实际运行代码并对其进行测试,并且仅基于您上面的 cmets,我相信您所说的部分是这样的:

//take away the usersMoney
self.takeAwayMoney(self.amountBets[indexPath.row],index: indexPath.row, completion:(result) in
    if result 
        // User has money
     else 
        // User does not have money
    
    var getResult = ""
    print("You have taken away the users money")

        print("you made it this far almost there")
        //let delayInSeconds = 3.0 // 1
        //DispatchQueue.main.asyncAfter(deadline: .now() + delayInSeconds)  // 2
)

takeAwayMoney 方法通过闭包的result 参数返回用户是否有钱,并且该参数在方法定义中不是可选的。但是,在上面的代码中,由于某种原因,它被声明为可选的。我更改了代码以删除那段代码,并添加了一个if 条件,指示在执行takeAwayMoney 后您将如何继续。

基本上,您首先调用takeAwayMoney,等待该方法通过闭包返回其结果,然后查看闭包的结果并进行任何后续处理。因此,看起来您确实需要将 if (self.userHasMoney == true) 条件中的所有代码移动到 takeAwayMoney 完成闭包中。

希望这是有道理的。如果没有,请随时联系我,我会尽力澄清。

【讨论】:

但如果我这样做,那么我将有嵌套的闭包并且代码将运行 10 次 @DevinTripp 不,只是嵌套闭包不会让它们运行多次。仅当代码的设置方式存在问题时,它们才会运行多次 :) 所以,我建议您设置我提到的方式,看看会发生什么。如果您遇到问题,请更新 GitHub 上的代码并告诉我,我会看看。

以上是关于为啥我的代码在完成块中运行两次的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的不和谐机器人只执行一次我的命令,而且只执行一次?

为啥console.log in react 运行两次

为啥 Xcode 将我的所有代码编译两次,导致任何全局变量的链接器错误?

按钮需要单击两次才能工作 - 为啥?

为啥我的程序接受用户输入的次数不超过两次?

SKPayments 完成交易两次调用