Helen Wood Helen Wood - 1 month ago 17
Objective-C Question

Delete UITable sections dynamically with commitEditingStyle in Swift

I’m dealing with an issue I can’t work around… I have a table of names, from a DB-array of customers, every customer has a name property among other data members.

I can delete rows within a section successfully, but what I can’t do it's deleting the section (when the last row within that section gets deleted, section must disappear).

I got:

'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of sections. The number of sections contained in the table view after the update (3) must be equal to the number of sections contained in the table view before the update (4), plus or minus the number of sections inserted or deleted (0 inserted, 0 deleted).

I know the table does some sanity checking behind the scenes of the data and this should match, but I can’t figurate exactly when, before calling deleteRowsAtIndexPaths? after? When should I update my property and/or dictionary? Should I manage numberOfSectionsInTableView data-source method?

I repeat, for rows deleting it’s working alright, the table moves out the row and gets updated properly. Last row on section is the deal...

I guess I'm missing something, that’s why I’m asking… Couldn’t find any help reading around either.

Thank you all very much!

func tableView(tableView: UITableView!, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath!) {
if (editingStyle == UITableViewCellEditingStyle.Delete) {
// handle delete (by removing the data from the array and updating the tableview)

//Check if delete was press
if editingStyle == .Delete {
//Delete row from dataSource
if let tv = tableView
{

customerList.removeAtIndex(returnPositionForThisIndexPath(indexPath, insideThisTable: tableView))
// Deletes the name of the customer from the customer list array, sorted by name

fillArrayOfNames()
//Fill the array of names for the sections-table, creating a dictionary with the name initials
//updated from the customer list array (below)

tv.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) //Crash in this line

tableView.reloadData()

}
}
}


func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return dictionaryOfPatientsInitials.count
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var keysFromDictionary = dictionaryOfPatientsInitials.keys.array

keysFromDictionary.sort(<)
let keyByOrder = keysFromDictionary[section]
let arrayInThisSection = dictionaryOfPatientsInitials[keyByOrder]

return arrayInThisSection!.count
}

Answer

You're almost there but you are going to need a way of detecting that a section has vanished, and which one has gone at which point you can call deleteSections

Bracket the update section in a beginUpdate / endUpdate call but do NOT call reloadData (See the docs for those methods about it)

/**
remove customer from model layer

:param: index index of customer to remove

:returns: return section that was removed or nil if none was
*/
func removeCustomer(index:Int)->Int? {

    var removedSectionOrNil:Int? = nil
    //logic to remove customer, rebuild model and detect if section has gone also
    return removedSectionOrNil

}

func tableView(tableView: UITableView!, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath!) {
    if (editingStyle == UITableViewCellEditingStyle.Delete) {
        // handle delete (by removing the data from the array and updating the tableview)

        //Check if delete was press
        if editingStyle == .Delete {
            //Delete row from dataSource
            if let tv = tableView
            {
                tv.beginUpdates()

                let position = returnPositionForThisIndexPath(indexPath, insideThisTable: tableView)
                let removedSection = removeCustomer(position)

                tv.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade) //Crash in this line

                if let removedSection = removedSection {
                    tv.deleteSections(sections:NSIndexSet(index: removedSection), withRowAnimation: .Automatic)
                }

                tv.endUpdates()

            }
        }
}

Without seeing the rest of your code , this should work but tableViews can be tricky when doing vanishing sections.