【问题标题】:Swift: Index out of range error for a table view while using firebaseSwift:使用firebase时表视图的索引超出范围错误
【发布时间】:2017-04-11 04:52:22
【问题描述】:

我正在创建一个应用程序,主要是为了学习语言。基本上我正在尝试制作一个应用程序,让您可以用CSGO 团队获胜的假钱下注。所以现在我在应用程序的一部分,允许用户创建一个赌注。然后用户可以看到他可以接受的所有赌注,然后接受另一个用户的赌注。我之前已经完成了所有这些工作,但我注意到了一个错误,所以我决定修复它。现在的问题是它崩溃了。

我需要该应用程序转到另一个屏幕,以便您可以对团队进行投注。然后您单击该框并设置您想对该特定球队下注多少。然后当您点击底部的提交Button时,它会将用户信息和投注信息上传到Firebase Database。然后它将返回上一个屏幕,显示所有尚未填写的赌注。所以他也应该。

问题是当我使用POPView 控制器返回到显示赌注的前一个视图控制器时,它给了我表格视图的索引超出范围错误。奇怪的是,如果我将方法 getBetsFor 移动到 viewDidLoad 而不是 view 将出现,那么它就可以正常工作。问题在于它会出现故障,并且不会显示用户刚刚下的赌注。

我知道我的代码很糟糕,我尝试将其中的一部分转换为 MVC 格式,但事不宜迟,这是我的代码。

下面的代码是从Firebase Database 获取投注然后将该数据放入对象数组中然后将对象显示到TableView 上的代码

  //
//  BetView.swift
//  EDraft
//
//  Created by Devin Tripp on 3/20/17.
//  Copyright © 2017 Devin Tripp. All rights reserved.
//

import UIKit
import Foundation
import Firebase


class BetView: UIViewController, UITableViewDelegate, UITableViewDataSource{
    @IBOutlet weak var tableView: UITableView!
    @IBOutlet weak var teamOne: UILabel!
    @IBOutlet weak var teamTwo: UILabel!
    let datRef = FIRDatabase.database().reference(fromURL: "https://edraft-77b47.firebaseio.com/")


    var userMoney = String()

    let getData = GatherData()

    var testies: String?

    var teamTOne = String()
    var teamTTwo = String()

    let screenSize: CGRect = UIScreen.main.bounds

    let navBar: UINavigationBar = UINavigationBar(frame: CGRect(x: 0, y: 60, width: UIScreen.main.bounds.width, height: 50))
    var navItem = UINavigationItem(title: "Money: ")


    let doneItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.add, target: nil, action: #selector(sayHello(sender:)))


    let backItem = UIBarButtonItem(barButtonSystemItem: UIBarButtonSystemItem.done, target: nil, action: #selector(goBack(sender:)))


    override func viewWillAppear(_ animated: Bool) {
        self.getData.betObjects.removeAll()
        self.getData.getBetsFor(completion: { (result) in
            if result == true {
                //show the spinning wheel thing
                self.tableView.reloadData()
            } else {
                // error
            }

        })
    }

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.addSubview(navBar)
        self.tableView.separatorStyle = .none

        navItem.rightBarButtonItem = doneItem
        navItem.leftBarButtonItem = backItem
        navBar.setItems([navItem], animated: false)

        teamOne.text = teamTOne
        teamTwo.text = teamTTwo


        /*
        getData.getBetsFor(completion: { (result) in
            if result == true {




                self.tableView.reloadData()
            } else {

            }

        })
        */

        getData.getMoneyFromUser(username: self.getData.userName, completion: { (money) in

            if money == true {
                let usermoney = String(self.getData.userMoney)
                //update the UI
                self.navItem.title = "$" + usermoney
                print(self.getData.userMoney)
            } else {
                print("no money found")
            }



        })

    }




    func tableView(_ tableView: UITableView, shouldUpdateFocusIn context: UITableViewFocusUpdateContext) -> Bool {
        return true
    }




    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
            let username = value?["username"] as? String
            self.getData.userName = username!
            // ...


            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.getData.userName)")
                    return
                }
                let values = ["OpposingUsername": self.getData.userName,"Show": "no"]
                //var val = self.getData.betObjects[index]
                //val.opposingUserName = self.getData.userName
            self.datRef.child("Bets").child(self.getData.tieBetToUser[index]).observeSingleEvent(of: .value, with: { (snapshot) in

                    let anothaValue = snapshot.value as? NSDictionary
                    let user = anothaValue?["Username"] as? String

                    if user == self.getData.userName {
                        // let the user know he cannot bet his own bet
                        completion(false)
                    } else {
                        self.datRef.child("Bets").child(self.getData.tieBetToUser[index]).updateChildValues(values)
                        completion(true)
                    }


                })



            })


        }) { (error) in
            print(error.localizedDescription)
        }


    }

    func getOpoosingUserNames(_ username: String,_ index: Int, completion: @escaping (_ result: 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
            let username = value?["username"] as? String ?? ""


            self.datRef.child("Bets").child(self.getData.tieBetToUser[index]).observeSingleEvent(of: .value, with: { snapshot in
                let thisValue = snapshot.value as? NSDictionary
                if let thisUserName = thisValue?["Username"] as? String {

                    self.getData.opposingUserName  = thisUserName
                    completion(true)


                } else {
                    completion(false)
                }

            })
        }) { (error) in
            print(error.localizedDescription)
        }
    }




    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        //if makeEmpty == true {
        //    return 0
        //} else {
        print(self.getData.betObjects.count)
            return self.getData.betObjects.count
        //}
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = self.tableView.dequeueReusableCell(withIdentifier: "cellB", for: indexPath) as! CellB
        print(self.getData.betObjects[indexPath.row].userName)
        cell.userNameLabel?.text = getData.betObjects[indexPath.row].userName
        cell.amountOfBet?.text = getData.betObjects[indexPath.row].betAmount


        return cell

    }


    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        let alertController = UIAlertController(title: "Accept Bet", message: "Match the bet of " + getData.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.getData.amountBets[indexPath.row],index: indexPath.row, completion: { (result) in

                if result == true {
                    self.updateBet(indexPath.row, completion: { (result) in


                        if result == true {
                            self.getOpoosingUserNames(self.getData.userName, indexPath.row, completion: { (anothaResult) in

                                if anothaResult == true {
                                    self.dismiss(animated: true, completion: {
                                        let successController = UIAlertController(title: "Success", message: "You have made a bet with " + self.getData.opposingUserName, 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

                                        let pathIndex = IndexPath(item: indexPath.row, section: 0)
                                        self.getData.betObjects.remove(at: indexPath.row)
                                        self.tableView.deleteRows(at: [pathIndex], with: .fade)
                                        self.tableView.reloadData()
                                        print("Second")
                                    })

                                    self.getData.getMoneyFromUser(username: self.getData.userName, completion: { (money) in

                                        if money == true {
                                            self.userMoney = String(self.getData.userMoney)
                                            //update the UI
                                            self.navItem.title = "$" + self.userMoney



                                            print(self.userMoney)
                                        } else {
                                            print("no money found")
                                        }



                                    })
                                } else {

                                }
                                //wait for the first view to load in case it uploads to fast


                            })

                        } else {
                            self.dismiss(animated: true, completion: {
                                let cannotBet = UIAlertController(title: "Failed", message: "You cannot bet with yourself dummy", preferredStyle: .alert)
                                let okButt = UIAlertAction(title: "Ok", style: .default, handler: nil)
                                cannotBet.addAction(okButt)
                                self.present(cannotBet, animated: true, completion: nil)
                            })
                        }


                    })



                } else {
                    // user doesn't have money
                    //display a alert that lets the user know hes broke
                    print("this should print once")
                    self.dismiss(animated: true, completion: {
                        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)
                    })
                }
                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
            })


        return
        })

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

    func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        return true
    }

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        if(editingStyle == UITableViewCellEditingStyle.delete) {
            self.getData.betObjects.remove(at: indexPath.row)
        }
    }


    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        //let indexPath = self.tableView.indexPathForSelectedRow!
        //var DestViewController : addBets = segue.destination as! addBets
        //DestViewController.teamOne = self.teamOne.text!
        //DestViewController.teamOne = self.teamTTwo

        if segue.identifier == "gotobetview" {
            if let destination = segue.destination as? addBets {

                destination.teamOne = self.teamOne.text!
                destination.teamTwo = self.teamTwo.text!
            }
        }




    }

    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)
                    }

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

    func getUserName() -> String {
        let userID = FIRAuth.auth()?.currentUser?.uid
        var useruser: String!
        datRef.child("User").child(userID!).observeSingleEvent(of: .value, with: { (snapshot) in
            // Get user value
            let value = snapshot.value as? NSDictionary
            let username = value?["username"] as? String ?? ""

            self.getData.userName = username
            useruser = username

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

        return useruser
    }




    func sayHello(sender: UIBarButtonItem) {
        let userInput = self.teamOne.text

        var userInputArray: [String] = []
        userInputArray.append(self.teamOne.text!)
        userInputArray.append(self.teamTwo.text!)
        performSegue(withIdentifier: "gotobetview", sender: userInputArray)





        //let storyboard = UIStoryboard(name: "Main", bundle: nil)
        //let homeView = storyboard.instantiateViewController(withIdentifier: "addBets")
        //self.present(homeView, animated: true, completion: nil)
    }

    func goBack(sender: UIBarButtonItem) {
        let storyboard = UIStoryboard(name: "Main", bundle: nil)
        let backView = storyboard.instantiateViewController(withIdentifier: "tabview")
        self.present(backView, animated: true, completion: nil)
    }

}

由于我无法发布更多代码,我将在 github 上更新项目并在此处发布链接。

https://github.com/devintrippprojects/EDraft

如果您下载该项目,您可以随时创建自己的帐户,您将从 100 美元开始,或者您可以使用电子邮件所在的主测试帐户 k@k.com 密码是 呸呸呸

明天我将发布数据库的外观和应用程序的外观,谢谢晚安。

【问题讨论】:

    标签: ios swift uitableview firebase firebase-realtime-database


    【解决方案1】:

    我下载并运行了你的项目。

    似乎这里的问题是您应该在删除所有数据源时重新加载 tableView。

    改变这个:

        self.getData.betObjects.removeAll()
        self.getData.getBetsFor(completion: { (result) in
            if result == true {
                //show the spinning wheel thing
                self.tableView.reloadData()
            } else {
                // error
            }
    
        })
    

    到这里:

        self.getData.betObjects.removeAll()
        self.tableView.reloadData()
        self.getData.getBetsFor(completion: { (result) in
            if result == true {
                //show the spinning wheel thing
                self.tableView.reloadData()
            } else {
                // error
            }
    
        })
    

    加一行:

    self.tableView.reloadData()
    

    【讨论】:

    • LOL 一行代码解决了整个问题。有没有一些网站可以更详细地解释表格视图,我大多明白,但这样的东西对我来说很疯狂。
    • 对于一般用法,我会推荐 Ray Wenderlich 的教程,但是对于这种鬼鬼祟祟的东西,我想只能从经验中学习:(
    • 还有另一个我无法解决的错误我很确定它与删除单元格有关。有时,这样做是非常随机的,但是假设您在应用程序上有三个赌注,第一个赌注是 10,第二个赌注是 20,第三个赌注是 30 有时当您单击显示 20 的赌注时,它会说匹配投注 10,如果您点击 30 投注,它会显示匹配投注 20。只有当您已经点击另一个投注并与他们进行投注时才会发生这种情况。
    • 无效更新:第0节中的行数无效。更新后现有节中包含的行数(10)必须等于更新前该节中包含的行数( 15),加上或减去从该节插入或删除的行数(0 插入,1 删除),加上或减去移入或移出该节的行数(0 移入,0 移出)。这是你得到的巨大错误
    • 等等,我想我已修复它我想我只需要在有人打赌我只是删除行之后,从数据库中更新表视图中的数据
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-08-06
    • 1970-01-01
    • 2017-04-03
    • 1970-01-01
    • 2016-08-15
    • 1970-01-01
    相关资源
    最近更新 更多