swiftuitableviewswift2nsindexpathexc-bad-instruction

Index out of range for indexPath swift


I am making an app that requires the user to tap on multiple cells in order to select them. when they tap on a cell, a .Checkmark accessory item will appear. For some reason though whenever I try and get to that VC the app crashes and I get the following error messages on line 8(if !checked[indexPath.row]):Bad Instruction error

Index out of range

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell
    {
        let cell: InstrumentTableCell! = tableView.dequeueReusableCellWithIdentifier(identifier) as? InstrumentTableCell


        cell.configurateTheCell(recipies[indexPath.row])

        if !checked[indexPath.row] {
            cell.accessoryType = .None
        } else if checked[indexPath.row] {
            cell.accessoryType = .Checkmark
        }
        return cell
    }

and this is my working checked method:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath)
    {
        tableView.deselectRowAtIndexPath(indexPath, animated: true)
        if let cell = tableView.cellForRowAtIndexPath(indexPath) {
            if cell.accessoryType == .Checkmark {
                cell.accessoryType = .None
                checked[indexPath.row] = false
            } else {
                cell.accessoryType = .Checkmark
                checked[indexPath.row] = true
            }
        }
    }

Solution

  • Your problem is that you only store items in your checked array when tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) is called. However, that method is only called when you actually select a row.

    tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) on the other hand is called each and every time you need to render a new table cell.

    So when you in cellForRowAtIndexPath asks:

    if !checked[indexPath.row]
    

    then you can not be sure that checked actually contains anything. For instance the first time you start rendering your cells, your checked array does not contain any values and therefore it crashes when you ask it for a value on a position that it does not have a value for.

    One solution could be to initialize your checked array to contain all false values. I'm guessing you have some model array called recipies so you could do something like:

    for (index, _) in recipies.enumerate() {
        checked.append(false)
    }
    

    Or as @AaronBrager suggests in the comments below (which is way prettier :))

    checked = Array(count:recipies.count, repeatedValue:false)
    

    that way you are sure that your checked array is properly initialized with the same number of elements as you have recipies.

    Another option could be to let the individual elements in recipies know whether or not they are checked.

    Hope this makes sense and helps you.