滚动/索引超出数组边界时,UITableView崩溃

时间:2017-12-05 15:09:19

标签: ios swift xcode uitableview

当我滚动UITableView时出现索引越界异常,bug似乎出现在名为checkTypes的函数中。 问题出在这一行:

listOfAllCells[i].cellTextBox.text = "\(value)"

这是我的ValuesTableViewController,带有自定义ValuesCell。

    //
//  ValuesTableViewController.swift
//  UnitConverter
//
//

import UIKit

protocol Initializable {
    init()
}
//Treba odraditi kalkulaciju unita za svaki treba popraviti bug koji se desi kod nasledjivanja

class ValuesTableViewController: UITableViewController, Initializable, UITextFieldDelegate {

    @IBOutlet var valuesTableView: UITableView!
    var valueName: String?
    var selectedValueObject: Properties?
    var listOfAllUnitObjects = [AnyObject]()
    var doubleTextValue : Double?
    var listOfAllCells = [ValuesCell]()
    var returningCalculatedValue : Double?
   // var testTextField : UITextField
    //"m²","km²","ha","dm²","cm²","mm²","sq mi", "ac", "sq yd","sq ft", "sq in"
   // var areaValues: [String: Area] = ["m²": Acre(), "km²": SquareKilometer(), "ha": Hectare(), "dm²": SquareDecimeter(), ""]
    //var listOfAllUnitsInClass = [Acre,Hectare,SquareCentimeter,SquareDecimeter,SquareFoot,SquareInch,]





    override func viewDidLoad() {
        super.viewDidLoad()

        // Uncomment the following line to preserve selection between presentations
        // self.clearsSelectionOnViewWillAppear = false

        // Uncomment the following line to display an Edit button in the navigation bar for this view controller.
        // self.navigationItem.rightBarButtonItem = self.editButtonItem
         valuesTableView.register(UINib(nibName: "ValuesCell", bundle: nil), forCellReuseIdentifier: "valueCell")


//        let myclass = stringClassFromString(valuesObject.textValue) as! Properties
//        let instance = myclass.init()
       // print("All units in selected Class : \(listOfAllUnitObjects)")
//       let testLista = testCalculation()
//        for object in testLista {
//            print("Ovo pokusavam da napravim : \(object)")
////        object as! Properties
////        let newType = type(of: object)
////        let createObject = createInstance(typeThing: newType)
//        /*
//        let acreTest = Acre()
//        print(acreTest.ConvertFromMainUnitToUnit(entryValue: 200))
//        print(testLista)
//         */

//        }
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    // MARK: - Table view data source

//    override func numberOfSections(in tableView: UITableView) -> Int {
//        // #warning Incomplete implementation, return the number of sections
//        return 0
//    }

    override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // #warning Incomplete implementation, return the number of rows
        let valuesType = configureTable()
        let valuesObject = createInstance(typeThing: valuesType)

      return valuesObject.listOfMainLabels.count

    }
    func textFieldDidBeginEditing(_ textField: UITextField) {
        textField.text = ""
    }
    func textFieldDidEndEditing(_ textField: UITextField) {
        //Ovde nastaje problem jer uzima prethodno unetu vrednost umesto novu

        //if textField.text != "" {
            if let textInputValue = textField.text {
                if Double(textInputValue) != nil {
                    if let doubleTextValueInput = Double(textInputValue){
                        doubleTextValue = doubleTextValueInput
                        //vratiti vrednost textfielda nakon promene da bi se input iskoristio za racunanje
                        let valuesType = configureTable()
                        let valuesObject = createInstance(typeThing: valuesType)
                        if let returnCalculatedValue = returningCalculatedValue {
                            checkTypes(allCells: listOfAllCells, entryValues: returnCalculatedValue, valuesObject: valuesObject)
                            print("Prolazi unesena vrednost za novo racunanje je \(returnCalculatedValue)")
                            valuesTableView.reloadData()
                        }
                        self.view.endEditing(true)
                    }

                }
            }
        //}
    }
    func configureTable() -> Properties.Type {

        //Check to see if the sent string is equal to any of the existing objects
        //if it is equal then create that object and append all of its values to tableView


        //Napravi listu svih objekata pusti u petlju iteraciju vidi da li je string jednak
        //nekom od objekata.text ako jeste stopiraj je i kraj
        if let valueNameUnwrapped = valueName {
        let valueNamesTrimmed = valueNameUnwrapped.trimmingCharacters(in: .whitespaces)
//            print("This is 2nd step: \(valueNamesTrimmed)")
        let allValuesList = AllValues()
        for value in allValuesList.listValues {
            //print("Vrednosti \(value.textValue)")
            switch valueNamesTrimmed {
            case value.textValue:
//                print("Izabrano je \(value.textValue)")
                selectedValueObject = value
                if let selectedObject = selectedValueObject{
                    selectedValueObject?.textValue = value.textValue
                   // selectedValueObject?.colorValue = value.colorValue
                    selectedValueObject?.tagValue = value.tagValue
                    let typeOfObject = type(of: selectedObject)
                    return typeOfObject
                }
            default:
                if let selectedObject = selectedValueObject{
                    selectedValueObject?.textValue = value.textValue
                   // selectedValueObject?.colorValue = value.colorValue
                    selectedValueObject?.tagValue = value.tagValue
                    let typeOfObject = type(of: selectedObject)
                    return typeOfObject
                }
            }
        }
        }
        return type(of: selectedValueObject) as! Properties.Type
    }


    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "valueCell", for: indexPath) as! ValuesCell
        if indexPath.row == 0 {
            cell.cellView.backgroundColor = UIColor.white
        }
        let valuesType = configureTable()
        let valuesObject = createInstance(typeThing: valuesType)

        let currentClassName = valuesObject.listOfAllUnits[indexPath.row]
        let unitObject = stringClassFromString(currentClassName)

        //Napraviti da u izabranom Unitu Navigacija bude iste boje kao na prethodnom screenu
        cell.cellMainLbl.text = valuesObject.listOfMainLabels[indexPath.row]
        cell.cellSmallLbl.text = valuesObject.listofSmallLabels[indexPath.row]
//            cell.valueLabel.textColor = UIColor.init(red: CGFloat(rColorValue[indexPath.row]), green: CGFloat(gColorValue[indexPath.row]), blue: CGFloat(bColorValue[indexPath.row]), alpha: 1.0)
//            cell.leftColorView.backgroundColor = UIColor.init(red: CGFloat(rColorValue[indexPath.row]), green: CGFloat(gColorValue[indexPath.row]), blue: CGFloat(bColorValue[indexPath.row]), alpha: 1.0)
        cell.tag = indexPath.row
        listOfAllCells.append(cell)
        //listOfAllUnitObjects.append(unitObject)
        if let unitObjectUnwrapped = unitObject {
            listOfAllUnitObjects.append(unitObjectUnwrapped)
        }
//        for unit in valuesObject.listOfAllUnits {
//            let unitObject = stringClassFromString(unit)
//            if let unitObjectUnwrapped = unitObject {
//                listOfAllUnitObjects.append(unitObjectUnwrapped)
//            }
//
//
//        }

//        //cell.imageView?.image = UIImage(named: fruitName)
//        cell.rightValueImage.image = UIImage(named: "\(indexPath.row)")

        // Configure the cell...
        return cell
    }
    override func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
        let valuesType = configureTable()
        let valuesObject = createInstance(typeThing: valuesType)
        checkTypes(allCells: listOfAllCells,entryValues: 1, valuesObject: valuesObject)
        valuesTableView.tableFooterView = UIView()
    }
    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {

        let valuesType = configureTable()
        let valuesObject = createInstance(typeThing: valuesType)
        let cell = tableView.cellForRow(at: indexPath) as! ValuesCell
        if indexPath.row != 0 {
           //let changeFirstCellColor = getCellsData()
         //   changeFirstCellColor[0].cellView.backgroundColor = UIColor.init(red: 232, green: 232, blue: 232, alpha: 1)

        }
        cell.cellView.backgroundColor = UIColor.white
//        print("Ovo su glavne vrednosti za racunanje \(listOfAllUnitObjects)")
//        let finalList = listOfAllUnitObjects as? [Properties]
//        print("Ovde je bio pucao program: \(String(describing: finalList))")
//        let mainToUnit = finalList[indexPath.row].ConvertFromMainUnitToUnit(entryValue: 20)
//        let unitToMain = finalList[indexPath.row].ConvertFromUnitToMainUnit(entryValue: 20)
//        cell.cellTextBox.value(forKey: "\(mainToUnit)")
        cell.cellTextBox.delegate = self
        if let doubleValue = doubleTextValue{
            //Ovde nastaje problem jer samo vrati unetu vrednost
            let entryValueReturned = checkTypesForSelected(indexPath: indexPath, cell: cell, entryValues: doubleValue, valuesObject: valuesObject)
            returningCalculatedValue = entryValueReturned
            if let returnCalculatedValue = returningCalculatedValue {
                print("Vracam vrednost od rezultata checkTypes funkcije za uneti broj \(doubleValue) rezultat je : \(returnCalculatedValue)")
            }


        }
        self.view.endEditing(true)


    }
    func checkTypes<T>(allCells: [ValuesCell],entryValues: Double, valuesObject: T){
        if valuesObject is Area {


        let classValues: [Area.Type] = [SquareMeter.self, SquareKilometer.self, Hectare.self, SquareDecimeter.self,
                                        SquareCentimeter.self, SquareMillimeter.self, SquareMile.self, Acre.self,
                                        SquareYard.self, SquareFoot.self, SquareInch.self]

            for i in 0...(listOfAllCells.count - 1){
                let object = classValues[i].init()
                let value = object.ConvertFromMainUnitToUnit(entryValue: entryValues)
                print("Vracam vrednost druge metode za \(i) element je : \(value)")
                listOfAllCells[i].cellTextBox.text = "\(value)"
            }
        }

    }
    func checkTypesForSelected<T>(indexPath: IndexPath, cell: ValuesCell,entryValues: Double, valuesObject: T) -> Double{
        if valuesObject is Area {

            let classValues: [Area.Type] = [SquareMeter.self, SquareKilometer.self, Hectare.self, SquareDecimeter.self,
                                            SquareCentimeter.self, SquareMillimeter.self, SquareMile.self, Acre.self,
                                            SquareYard.self, SquareFoot.self, SquareInch.self]
            if listOfAllUnitObjects[indexPath.row] is SquareMeter.Type {
                var testObject = classValues[indexPath.row].init()
                testObject = createInstance(typeThing: (listOfAllUnitObjects[indexPath.row] as? SquareMeter.Type)!)
                print("Zavrseno RADI! \(testObject)")
                let value = testObject.ConvertFromUnitToMainUnit(entryValue: entryValues)
                cell.cellTextBox.text = "\(value)"
                return value
            } else if listOfAllUnitObjects[indexPath.row] is SquareKilometer.Type {
                var testObject = classValues[indexPath.row].init()
                testObject = createInstance(typeThing: (listOfAllUnitObjects[indexPath.row] as? SquareKilometer.Type)!)
                print("Zavrseno RADI! \(testObject)")
                let value = testObject.ConvertFromUnitToMainUnit(entryValue: entryValues)
                cell.cellTextBox.text = "\(value)"
                return value
            }else if listOfAllUnitObjects[indexPath.row] is Hectare.Type{
                var testObject = classValues[indexPath.row].init()
                testObject = createInstance(typeThing: (listOfAllUnitObjects[indexPath.row] as? Hectare.Type)!)
                print("Zavrseno RADI! \(testObject)")
                let value = testObject.ConvertFromUnitToMainUnit(entryValue: entryValues)
                cell.cellTextBox.text = "\(value)"
                return value
            }else if listOfAllUnitObjects[indexPath.row] is SquareDecimeter.Type{
                var testObject = classValues[indexPath.row].init()
                testObject = createInstance(typeThing: (listOfAllUnitObjects[indexPath.row] as? SquareDecimeter.Type)!)
                print("Zavrseno RADI! \(testObject)")
                let value = testObject.ConvertFromUnitToMainUnit(entryValue: entryValues)
                cell.cellTextBox.text = "\(value)"
                return value
            }else if listOfAllUnitObjects[indexPath.row] is SquareCentimeter.Type{
                var testObject = classValues[indexPath.row].init()
                testObject = createInstance(typeThing: (listOfAllUnitObjects[indexPath.row] as? SquareCentimeter.Type)!)
                print("Zavrseno RADI! \(testObject)")
                let value = testObject.ConvertFromUnitToMainUnit(entryValue: entryValues)
                cell.cellTextBox.text = "\(value)"
                return value
            }else if listOfAllUnitObjects[indexPath.row] is SquareMillimeter.Type{
                var testObject = classValues[indexPath.row].init()
                testObject = createInstance(typeThing: (listOfAllUnitObjects[indexPath.row] as? SquareMillimeter.Type)!)
                print("Zavrseno RADI! \(testObject)")
                let value = testObject.ConvertFromUnitToMainUnit(entryValue: entryValues)
                cell.cellTextBox.text = "\(value)"
                return value
            }else if listOfAllUnitObjects[indexPath.row] is SquareCentimeter.Type{
                var testObject = classValues[indexPath.row].init()
                testObject = createInstance(typeThing: (listOfAllUnitObjects[indexPath.row] as? SquareCentimeter.Type)!)
                print("Zavrseno RADI! \(testObject)")
                let value = testObject.ConvertFromUnitToMainUnit(entryValue: entryValues)
                cell.cellTextBox.text = "\(value)"
                return value
            }else if listOfAllUnitObjects[indexPath.row] is SquareMile.Type{
                var testObject = classValues[indexPath.row].init()
                testObject = createInstance(typeThing: (listOfAllUnitObjects[indexPath.row] as? SquareMile.Type)!)
                print("Zavrseno RADI! \(testObject)")
                let value = testObject.ConvertFromUnitToMainUnit(entryValue: entryValues)
                cell.cellTextBox.text = "\(value)"
                return value
            }else if listOfAllUnitObjects[indexPath.row] is Acre.Type{
                var testObject = classValues[indexPath.row].init()
                testObject = createInstance(typeThing: (listOfAllUnitObjects[indexPath.row] as? Acre.Type)!)
                print("Zavrseno RADI! \(testObject)")
                let value = testObject.ConvertFromUnitToMainUnit(entryValue: entryValues)
                cell.cellTextBox.text = "\(value)"
                return value
            }else if listOfAllUnitObjects[indexPath.row] is SquareYard.Type{
                var testObject = classValues[indexPath.row].init()
                testObject = createInstance(typeThing: (listOfAllUnitObjects[indexPath.row] as? SquareYard.Type)!)
                print("Zavrseno RADI! \(testObject)")
                let value = testObject.ConvertFromUnitToMainUnit(entryValue: entryValues)
                cell.cellTextBox.text = "\(value)"
                return value
            }else if listOfAllUnitObjects[indexPath.row] is SquareFoot.Type{
                var testObject = classValues[indexPath.row].init()
                testObject = createInstance(typeThing: (listOfAllUnitObjects[indexPath.row] as? SquareFoot.Type)!)
                print("Zavrseno RADI! \(testObject)")
                let value = testObject.ConvertFromUnitToMainUnit(entryValue: entryValues)
                cell.cellTextBox.text = "\(value)"
                return value
            }else if listOfAllUnitObjects[indexPath.row] is SquareInch.Type{
                var testObject = classValues[indexPath.row].init()
                testObject = createInstance(typeThing: (listOfAllUnitObjects[indexPath.row] as? SquareInch.Type)!)
                print("Zavrseno RADI! \(testObject)")
                let value = testObject.ConvertFromUnitToMainUnit(entryValue: entryValues)
                cell.cellTextBox.text = "\(value)"
                return value
            }

        }
        return 0
    }
//    func calculateAllUnits(){
//        let allCells = getCellsData()
//        for cell in allCells {
//            cell.cellTextBox.text = ""
//        }
//    }
    //Pravi objekat od typa Klase
    func createInstance<T>(typeThing:T.Type) -> T where T:Initializable {
        return typeThing.init()
    }

    func stringClassFromString(_ className: String) -> AnyClass! {

        /// get namespace
        let namespace = Bundle.main.infoDictionary!["CFBundleExecutable"] as! String;

        /// get 'anyClass' with classname and namespace
        let cls: AnyClass = NSClassFromString("\(namespace).\(className)")!;

        // return AnyClass!
        return cls;
    }
//    func getCellsData() -> [ValuesCell] {
//        var dataArray: [ValuesCell] = []
//        for section in 0 ..< self.valuesTableView.numberOfSections {
//            for row in 0 ..< self.valuesTableView.numberOfRows(inSection: section) {
//                let indexPath = NSIndexPath(row: row, section: section)
//                let cell = self.valuesTableView.cellForRow(at: indexPath as IndexPath) as! ValuesCell
//                dataArray.append(cell)
//            }
//        }
//        return dataArray
//    }

    //Neka prikaze ne keyboard sa slovima nego samo sa brojkama da ogranicimo korisnika
//    func textFieldDidBeginEditing(_ textField: UITextField) {
//
//    }
//    func textFieldDidEndEditing(_ textField: UITextField) {
//        <#code#>
//    }
//    func testCalculation() -> [AnyObject]{
//        let valuesType = configureTable()
//        let valuesObject = createInstance(typeThing: valuesType)
//        let list = valuesObject.listOfAllUnits
//        var listOfAllUnitValues = [AnyObject]()
//        print("Broj koliko ima elementa u listi : \(list.count)")
//        for i in 0...(list.count - 1) {
//            let object1 = stringClassFromString(list[i]) as AnyObject
//            listOfAllUnitValues.append(object1)
//        }
//        return listOfAllUnitValues
//
//    }
    //Napraviti Dictionary key value da bude labela iz celije, a vrednost da bude ta klasa, posle povezati
//    func makeAllUnitObjects() -> [Properties] {
//       let listOfAllCells = getCellsData()
//        for i in 0...listOfAllCells.count {
//            let test = listOfAllCells[i]
//        }
//    }
    /*
    // Override to support conditional editing of the table view.
    override func tableView(_ tableView: UITableView, canEditRowAt indexPath: IndexPath) -> Bool {
        // Return false if you do not want the specified item to be editable.
        return true
    }
    */

    /*
    // Override to support editing the table view.
    override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        if editingStyle == .delete {
            // Delete the row from the data source
            tableView.deleteRows(at: [indexPath], with: .fade)
        } else if editingStyle == .insert {
            // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
        }    
    }
    */

    /*
    // Override to support rearranging the table view.
    override func tableView(_ tableView: UITableView, moveRowAt fromIndexPath: IndexPath, to: IndexPath) {

    }
    */

    /*
    // Override to support conditional rearranging of the table view.
    override func tableView(_ tableView: UITableView, canMoveRowAt indexPath: IndexPath) -> Bool {
        // Return false if you do not want the item to be re-orderable.
        return true
    }
    */

    /*
    // MARK: - Navigation

    // In a storyboard-based application, you will often want to do a little preparation before navigation
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Get the new view controller using segue.destinationViewController.
        // Pass the selected object to the new view controller.
    }
    */

}

1 个答案:

答案 0 :(得分:0)

我设法找出问题是什么,因为uitableview根据你可以看到多少个单元格生成单元格,我的listOfAllCells不断追加。修复在cellForRowAt:

if valuesObject.listOfMainLabels.count - 1 >= listOfAllCells.count {
            listOfAllCells.append(cell)
}

正如你所看到的1 if语句修复问题感谢回复这个帖子,如果有人对我的代码有任何建议我很乐意听到因为我刚开始开发我的初学者和每个建议让我变得更好。