0

I've got a static UITableView with two sections. When the user taps the cell at index 2 in section 1, a UITableViewCell needs to be added below the tapped cell. Each subsequent cell tap should result in another cell being added below any already added cells.

This is what I've tried so far, but I'm crashing with an NSRangeException stating that index 6 is beyond the available bounds so i'm clearly not updating the number of rows properly somehow..

As per Adding unknown number of rows to 'Static Cells' UITableView I've overridden all UITableView methods that use an indexPath but their situation is slightly different to mine.

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    if section == 1 {
        // subTaskRow is an array holding all the indexes of the added cells
        // so I know where to add the next one. I also know how many I've added
        return 6 + subTaskRow.count
    } else {
        return super.tableView(tableView, numberOfRowsInSection: section)
    }
}
override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    // If the Sub Task cell is picked
    if (indexPath.section == 1 && indexPath.row == 3) {
        // If this is the first subtask we want it to appear under Sub Tasks
        // We know the index of the cell below sub task so we can add it in directly
        if (subTaskRow.count == 0) {
            subTaskRow.addObject(5)
            tableView.insertRowsAtIndexPaths([NSIndexPath(forRow: 5, inSection: 1)], withRowAnimation: .Automatic)
            tableView.reloadData()
        // Other sub tasks should appear below previous sub tasks
        } else {
            // The last object in sub tasks will always be the
            // indexPath of the previous added cell
            let row = (subTaskRow.lastObject as! Int) + 1
            subTaskRow.addObject(row)
            tableView.insertRowsAtIndexPaths([NSIndexPath(forRow: row, inSection: 1)], withRowAnimation: .Automatic)
            tableView.reloadData()
        }
    }

    tableView.deselectRowAtIndexPath(indexPath, animated: true)
}

// Now we override all the other methods to ensure we don't get a crash
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    return false
}

override func tableView(tableView: UITableView, canMoveRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    return false
}

override func tableView(tableView: UITableView, editingStyleForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCellEditingStyle {
    return .None
}

override func tableView(tableView: UITableView, indentationLevelForRowAtIndexPath indexPath: NSIndexPath) -> Int {
    return super.tableView(tableView, indentationLevelForRowAtIndexPath: indexPath)
}

My guess would be that adding in a cell in the middle of a section doesn't update the indexPaths of the already existing cells or something? I'm not sure how I'd do that though.

Community
  • 1
  • 1
Chris Byatt
  • 3,689
  • 3
  • 34
  • 61
  • What does your cellForRowAtIndexPath method look like? Can you add it to your list of tableview methods? Also, in interface builder, do you have the "Index Row Limit" set? – erparker Jun 15 '15 at 21:52
  • @erparker I haven't actually used one because they are all static cells and there's nothing to configure... will I need to use it for the rows I'm adding in? – Chris Byatt Jun 15 '15 at 21:55
  • Another thing I noticed, are you trying to do your own subclass of UITableView? You've got override in front of all your tableview data source and delegate methods, which you don't need if you're just using a tableview as part of a view controller. – erparker Jun 15 '15 at 22:01
  • It's a UITableViewController. If I don't have override swift yells at me – Chris Byatt Jun 15 '15 at 22:02
  • Yeah, that's true. another question I have is why are you calling super.numberOfRows in your numberOfRowsatIndexPath method? I actually got this to work, but I had to change the way you handle sections – erparker Jun 15 '15 at 22:30

1 Answers1

1

I got this to work, but this code is only using one section:

override func numberOfSectionsInTableView(tableView: UITableView) -> Int {
        // #warning Potentially incomplete method implementation.
        // Return the number of sections.
        return 1
    }

override func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
    // subTaskRow is an array holding all the indexes of the added cells
    // so I know where to add the next one. I also know how many I've added
    return 6 + subTaskRow.count
}

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    // If the Sub Task cell is picked
    if (indexPath.section == 0 && indexPath.row == 3) {
        // If this is the first subtask we want it to appear under Sub Tasks
        // We know the index of the cell below sub task so we can add it in directly
        if (subTaskRow.count == 0) {
            subTaskRow.append(5)
            tableView.insertRowsAtIndexPaths([NSIndexPath(forRow: 5, inSection: 0)], withRowAnimation: .Automatic)
            tableView.reloadData()
            // Other sub tasks should appear below previous sub tasks
        } else {
            // The last object in sub tasks will always be the
            // indexPath of the previous added cell
            let row = subTaskRow.last! + 1
            subTaskRow.append(row)
            tableView.insertRowsAtIndexPaths([NSIndexPath(forRow: row, inSection: 0)], withRowAnimation: .Automatic)
            tableView.reloadData()
        }
    }

    tableView.deselectRowAtIndexPath(indexPath, animated: true)
}


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

    cell.textLabel!.text = "the row: \(indexPath.row)"

    return cell
}

try out this code and see if it works for you. From here, you just need to add the code to handle sections, which means adding code to numberOfSectionsInTableView. You shouldn't be calling super.numberOfRowsInTableview here because if you have 2 sections of data, you should know how many rows are in each

erparker
  • 1,301
  • 10
  • 21