Chapter 5 World Cup: How can I delete a team at row in section?

Hi all, here is a beginner´s question: How can I delete a World Cup team at row in section? [you explain a delete-function in the DogWalks-Chapter, but this function does not fit for the World Cup?]

First I put this function in the UITableViewDataSource:
func tableView(_ tableView: UITableView,
canEditRowAt indexPath: IndexPath) -> Bool {
return true
}
then this function in the NSFetchedResultsControllerDelegate:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {

        tableView.deleteRows(at: [indexPath], with: .left)
    }

}
Now on the simulator I can stroke to the left, but when I tap »delete«, the app crashes, but I cannot interprete, what the debug area says:
Terminating app due to uncaught exception ‘NSInternalInconsistencyException’, reason: ‘Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (2) must be equal to the number of rows contained in that section before the update (2), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).’

@bernhardp. Thanks very much for your question, and my apologies for the delayed reply. It appears that while you are deleting the row from the table, you unfortunately don’t seem to be making this change in your datastore, which is supposed to mirror the data being displayed in your UITableView. I believe you’re getting the error due to the inconsistency of the data you’re presenting in the UITableView, and what is contained in your collection. Remember to delete the same object from your data store, and that should solve your problem.

I hope that helps :slight_smile:

All the best!

I am seeing this too. Here’s my code and it crashes immediately as it runs the tableView.deleteRows(at: [indexPath], with: .automatic]

    override func tableView(_ tableView: UITableView,
                  commit editingStyle: UITableViewCellEditingStyle,
                  forRowAt indexPath: IndexPath) {
    
     if let context = (UIApplication.shared.delegate as? AppDelegate)?.persistentContainer.viewContext {
        guard let recipientToRemove =
            recipient[indexPath.row] as Recipient?,
            editingStyle == .delete else {
                return
        }
    
        context.delete(recipientToRemove)
    
        do {
            try context.save()
            
            tableView.deleteRows(at: [indexPath], with: .automatic)
            
        } catch let error as NSError {
            print("Saving error: \(error), description: \(error.userInfo)")
        }
    }
}

I am pulling in the context from my and when I step thru the code everything processes as expected except fir the deleteRows

@pietrorea Can you please help with this when you get a chance? Thank you - much appreciated! :]

1 Like

@theapapp Thanks very much for your question!

First off, I strongly advise against using the AppDelegate in order to obtain a reference to the ManagedObjectContext (MOC). You should use a local property which is set via dependency injection so that the necessary viewController receives the same object which is being used throughout the app.

Secondly, I would keep your guard statement for the object to delete outside of an if/let clause. So set the MOC using dependency injection, or initialize it using a separate Core Data Stack class (take a look at page 81 from Core Data By Tutorials book). After the MOC is set, then have your guard clause:

        guard let recipientToRemove =
            recipient[indexPath.row] as Recipient?,
            editingStyle == .delete else {
                return
        }

The rest of your code looks fine, so try that, and see what happens.

I hope this helps!

All the best!

1 Like