Sorry for the bad title, and I feel really dumb for asking this question.
I'm deleting a cell from my table and the first block of code runs just perfect, but when shortening the line by creating a variable the code crashes. Why?
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
emojisByCategories[indexPath.section].remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
This small change will cause a "libc++abi.dylib: terminating with uncaught exception of type NSException
(lldb)" error
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
var emojis = emojisByCategories[indexPath.section]
emojis.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .automatic)
}
}
Build on Xcode Version 9.0 (9A235)
You have an array of arrays. Array in Swift is a struct which is a value type. When you assign an array to another variable, you are actually creating a copy of the array.
When you do:
var emojis = emojisByCategories[indexPath.section]
emojis.remove(at: indexPath.row)
you are modifying the copy in emojis. Nothing in emojisByCategories is actually being changed as a result of this code.
So now you tell the table view that a row has been deleted but your data source hasn't actually changed at all so you get the crash telling you about an invalid number of rows in a section.
The line:
emojisByCategories[indexPath.section].remove(at: indexPath.row)
doesn't have the same problem because you are not making a copy of any array and the values in emojisByCategories are being updated as expected.
You can make your second set of code work by adding a third line:
var emojis = emojisByCategories[indexPath.section]
emojis.remove(at: indexPath.row)
emojisByCategories[indexPath.section] = emojis
That 3rd line updates emojisByCategories with the updated emojis array so now your code won't crash.
Related
Try to delete tableViewCell in swift XIB. but there is error cannot remove models
viewModel :
private var combinedItems: [combinedInboxModel] = []
func get(){} // Add combinedItems data
View Controller
override func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
viewModel.combinedItems.remove(at: indexPath.row) // No exact matches in call to instance method 'remove' in swift
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
Why there is error remove here?
I am making an app that stores events and their data, and it was working flawlessly until I tried to add Core Data, since then, I've been having issues with it. One is the fact that using the delete func doesn't really delete the tablecell, just the data inside. If I try to delete the blank cell, it does nothing. Below is the code for the delete function I am using.
Also, my app for some reason starts with one of these blank cell, which can't be deleted.
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
PersistenceService.context.delete(events[indexPath.row])
do {
try PersistenceService.context.save()
eventLog.reloadData()
} catch let error as NSError {
print("Could not save. \(error), \(error.userInfo)")
}
}
}
You have to remove the item from the context and from the data source array and it's highly recommended to use deleteRows rather than reloading the entire table view to take advantage of the animation
PersistenceService.context.delete(events[indexPath.row])
events.remove(at: indexPath.row)
eventLog.deleteRows(at: [indexPath], with: .fade)
... save context
So I'm trying to delete data from a tableView, which It will delete the cell at the row, but it won't delete the information from coreData, causing it to load again when I call a .reloadData(). I'm really new to coredata and I don't know how to select a specific Recipe item that I make.
Here's where I handle the delete:
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == UITableViewCellEditingStyle.delete) {
// handle delete (by removing the data from your array and updating the tableview)
recipes.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
}
}
Here's how I am creating the items in coreData, if this helps. Also, I have a Git repository here if anyone's willing to look that deep
#IBAction func createNewRecipeButton(_ sender: Any) {
let context = (UIApplication.shared.delegate as! AppDelegate).persistentContainer.viewContext
let newRecipe = Recipe(context: context)
newRecipe.title = recipeTitleTextBox.text
newRecipe.instructions = recipeInstructionsTextBox.text
newRecipe.time = recipeTimeTextBox.text
(UIApplication.shared.delegate as! AppDelegate).saveContext()
navigationController!.popToRootViewController(animated: true)
}
Your current removal method merely deletes the recipe from the storage array. You need to tell the context to get rid of it as well…
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if (editingStyle == UITableViewCellEditingStyle.delete) {
let recipe = recipes.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: UITableViewRowAnimation.automatic)
guard let moc = recipe.managedObjectContext else { return }
moc.delete(recipe)
moc.processPendingChanges()
}
}
You might also want to look into using a NSFetchedResultsController. There are several tutorials around.
I'm following this answer to get that nice faded deleted cell. Currently when I swipe to delete, it's sharp, sudden and ugly. Other apps has that nice fade when cell is deleted.
In my app, the cell is not really deleted, the data is removed:
Swift 3, func editingStyle:
let tableSection = sections[sortedSections[indexPath.section]]
let tableItem = tableSection![indexPath.row]
// Removes item from array:
self.incomesDictionary.removeValue(forKey: tableItem.incomeId)
// Reloading the table data:
self.tableView.reloadData()
When I add self.tableView.deleteRows(at: [indexPath], with: .fade) above the ...reloadData() I get an error:
terminating with uncaught exception of type NSException
If I update the function with tableSection?.remove(at: indexPath.row), it still crashes. Any tips to get that smooth effect?
Edit:
I have a programmatically grouped cell and the error I got, after adding the .fade is:
Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'attempt to delete row 0 from section 0, but there are only 0 sections before the update'
Swift 5.0
https://www.hackingwithswift.com/example-code/uikit/how-to-swipe-to-delete-uitableviewcells
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCell.EditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
self.myArray.remove(at: indexPath.row)
tableView.deleteRows(at: [indexPath], with: .fade)
}
}
Try this:
self.tableView.beginUpdates()
self.tableView.deleteRows(at: [indexPath], with: .fade)
self.tableView.endUpdates()
This will prepare the tableView for your animation
I'm trying to add functionality so the user can delete a table cell. However, this table cell is populated using a dictionary so I'm getting an error message: "cannot invoke 'removeAtIndex' with an argument list of type {index: Int)
Here's my code:
var titles = [Int: String]()
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
titles.removeAtIndex(index: indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
}
}
You need to call removeValueForKey method, because you use Int as keys. The
An you need to add beginUpdates and endUpdates method calls as well to perform the animations.
See the code below:
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == UITableViewCellEditingStyle.Delete {
table.beginUpdates()
titles.removeValueForKey(index: indexPath.row)
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: UITableViewRowAnimation.Automatic)
table.endUpdates()
}
}
Note: in such a case, consider using Array instead of Dictionary? You don't actually need dictionary since it will be indexed from row 0 to row count-1, right?