I am developing an IOS app. Delete the row in tableview and data load in core data in table view. When Click the delete button App crash.
Reason is reason: Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (18) must be equal to the number of rows contained in that section before the update (18), 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)...
_fetchedobj is an NSArray to Fetch data from core data
//Code is
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return _fetchedobj.count;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *MyIdentifier = #"MyReuseIdentifier";
UITableViewCell *cell = [myTable dequeueReusableCellWithIdentifier:MyIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:MyIdentifier];
}
data = [_fetchedobj objectAtIndex:indexPath.row];
return cell;
}
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[tableView beginUpdates];
NSManagedObject *managedObject = [_fetchedobj objectAtIndex:indexPath.row];
[self.managedObjectContext deleteObject:managedObject];
[myTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[myTable endUpdates];
}
}
Don't you forget to remove this object from your datasource array?
try repopulate your _fetchedobj because you must configure your model after deletion. For more detail, read https://developer.apple.com/library/prerelease/ios/documentation/UserExperience/Conceptual/TableView_iPhone/ManageInsertDeleteRow/ManageInsertDeleteRow.html
Try this
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath*)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[tableView beginUpdates];
NSManagedObject *managedObject = [_fetchedobj objectAtIndex:indexPath.row];
[self.managedObjectContext deleteObject:managedObject];
// insert this line to your code
NSMutableArray *newA = [_fetchedobj mutableCopy ];
[newA removeObjectAtIndex: indexPath.row];
_fetchedobj = newA;
[myTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[myTable endUpdates];
}
}
Try using this line for deleting row of table view
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
Related
I have UITableView and I made implementation for -(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath :
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
NSUInteger beforeDeleteCount = historyArray.count;
VideoItem *video = [historyArray objectAtIndex:indexPath.row];
[[HistoryRepository sharedHistory] removeFromHistories:video];
if (self.titleSort) {
[self sortArrayByTitleAtoZWithReloadData:NO];
} else {
[self sortArrayByNormalWithReloadData:NO];
}
NSUInteger afterDeleteCount = historyArray.count;
if (beforeDeleteCount == afterDeleteCount) {
[table reloadData];
} else {
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
}
-(void)sortArrayByNormalWithReloadData:(BOOL)reload {
self.titleSort = NO;
historyArray = [[NSMutableArray alloc] initWithArray:[[HistoryRepository sharedHistory] historyArray]];
if (reload) {
[self setTableHeader];
[table reloadData];
}
}
-(void)sortArrayByTitleAtoZWithReloadData:(BOOL)reload {
self.titleSort = YES;
NSSortDescriptor * sortDescriptor = [[[NSSortDescriptor alloc]initWithKey:#"name" ascending:YES selector:#selector(caseInsensitiveCompare:)] autorelease];
historyArray = [[NSMutableArray alloc] initWithArray:[[[HistoryRepository sharedHistory] historyArray] sortedArrayUsingDescriptors:#[sortDescriptor]]];
if (reload) {
[self setTableHeader];
[table reloadData];
}
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section{
return [historyArray count];
}
And I still get this kind of error all the time:
Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (27) must be equal to the number of rows contained in that section before the update (27), 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).
I always making a check if it's the same count so reload the table and don't delete but still i'm getting this error.
Reordering the data source array after deleting an item makes no sense if the array is already sorted.
And you must not call deleteRowsAtIndexPaths after reordering the data source array anyway.
This version of commitEditingStyle: is sufficient
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
VideoItem *video = [historyArray objectAtIndex:indexPath.row];
[[HistoryRepository sharedHistory] removeFromHistories:video];
[historyArray removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
Im trying to Delete row of custom cell , I have managed to delete the item from his class, but everytime that I remove the last row in the tableView (when i have only one for example), the cell is reset but not remove and i still see her in the view.
btw - reloadData not working for me.
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
static NSString *CellIdentifier = #"TableCell";
TableCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier forIndexPath:indexPath];
UITableViewCell *selectedCell = [tableView cellForRowAtIndexPath:indexPath];
cell = (TableCell*)selectedCell;
// Delete the row from the data source.
[User DeleteUserFromList:cell.Id];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [User GetUserList].count;
}
In my UIViewController, I have a table view whose cells show text. The datasource and delegate of the UITableView is my UIViewController. The text to be showed by the cells is stored in an NSMutableArray.
I am able to populate the cells with the text initially, but I also want to implement a functionality, when a user clicks on a specific row the cell gets removed and the table is reloaded.
Here's my code and it's details:
taskList is a NSMutableArray
png images are ones that i need to add in every cell
my table contains only one section
the last row of the table will always show "Create New Task" with a "+" sign as an image
as user adds other task (handled by a separate controller), the taask gets added to the current table.The task will have a "-" sign image.
When user clicks on such a row, it will get deleted from the table
UIViewController's code:
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
taskList = [[NSMutableArray alloc] init];
addNewTask = [[AddTaskViewController alloc] init];
[taskList addObject:#"Create New Task"];
[taskList addObject:#"aaaaa"];
[taskList addObject:#"bbbbb"];
[taskList addObject:#"ccccc"];
}
-(NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
indexNumberInTaskList = [taskList count] - 1;
return [taskList count];
}
-(UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
UITableViewCell *cell;
cell = [tableView dequeueReusableCellWithIdentifier:#"myCell"];
if(cell == nil)
{
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:#"myCell"];
}
if(indexNumberInTaskList >= 0)
{
cell.textLabel.text = [taskList objectAtIndex:indexNumberInTaskList];
if(indexPath.row == ([taskList count] - 1))
{
cell.imageView.image = [UIImage imageNamed:#"add.png"];
}
else
{
cell.imageView.image = [UIImage imageNamed:#"remove.png"];
}
indexNumberInTaskList = indexNumberInTaskList - 1;
}
return cell;
}
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
int selectedRow = indexPath.row;
if(selectedRow == ([taskList count]-1))
{
[self presentViewController:addNewTask animated:YES completion:NULL];
}
else
{
[taskList removeObjectAtIndex:indexPath.row];
[self.createDaily reloadData];
}
}
The least amount of code way would be:
-(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[self.modelArray removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationAutomatic];
}
These are only required to batch multiple changes together:
[tableView beginUpdates];
[tableView endUpdates];
You can use didSelectRowAtindexPath method of tableview
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[arrayData removeObjectAtIndex:indexPath.row];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow: indexPath.row inSection:0]] withRowAnimation:UITableViewRowAnimationRight];
[tableView endUpdates];
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[YourArr removeObjectAtIndex:indexPath.row];
[YourTbl reloadData];
}
Under your -(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath delegate method,
(void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath`
NSArray *toBeDeleted = [[NSArray alloc] initWithObjects: indexPath];
// Data deletion
[tableData removeObjectAtIndex:(indexPath.row)];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:toBeDeleted withRowAnimation:UITableViewRowAnimationFade];
[tableView endUpdates];
}
Edit: seems everybody has the same answer!
Add this method
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
[arrData removeObjectAtIndex:indexPath.row];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow: indexPath.row inSection:0]] withRowAnimation:UITableViewRowAnimationRight];
[tableView endUpdates];
}
I have an array (datasource) with a set of addresses, my tableview is set to have double the amount of cells from the datasource so I can style the odd cells to be small and clear (to make the tableview look like the cells are separated by a small space). My problem comes when deleting a row, I do the following:
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath{
[tableView beginUpdates];
if (editingStyle==UITableViewCellEditingStyleDelete) {
[self DeleteAddress:[ListAddress objectAtIndex:indexPath.row/2]];
[ListAddress removeObjectAtIndex: indexPath.row/2];
NSIndexPath *nextIndexPath = [[NSIndexPath alloc] initWithIndex:indexPath.row+1];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath,nextIndexPath,nil] withRowAnimation:UITableViewRowAnimationRight];
}else if (editingStyle == UITableViewCellEditingStyleInsert){
[self tableView:tableView didSelectRowAtIndexPath:indexPath];
}
[tableView endUpdates];
}
The DeleteAddress method deletes the address from the database.
When the debugger reaches the [tableview endUpdate] function a get the following error:
*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableView.m:1070
NSInternalInconsistencyException
Just follow the sample code.Delete one row from your data source.Hope its useful for you.This code works for my app.Try it
// Swipe to delete has been used. Remove the table item
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Get a reference to the table item in our data array
Pictures *itemToDelete = [self.pictureListData objectAtIndex:indexPath.row];
// Delete the item in Core Data
[self.managedObjectContext deleteObject:itemToDelete];
// Remove the item from our array
[pictureListData removeObjectAtIndex:indexPath.row];
// Commit the deletion in core data
NSError *error;
if (![self.managedObjectContext save:&error])
NSLog(#"Failed to delete picture item with error: %#", [error domain]);
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
My problem was that I was creating my nextIndexPath variable the wrong way. It should have been like this:
NSIndexPath *nextIndexPath = [NSIndexPath indexPathForRow:indexPath.row+1 inSection:indexPath.section];
Also I couldn't delete both rows at the same time, I needed to delete them separately from bottom:
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:nextIndexPath] withRowAnimation:UITableViewRowAnimationRight];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationRight];
Note: when I tap the row, then the app crashes.
I'm trying to implement adding a new cell on a user's tap. I found that there was a similar example in WWDC 2011's table view demonstration. Here's my code from my table view.
Here is the error:
2013-03-19 20:04:28.672 Project[51229:c07] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-2380.17/UITableView.m:1070
Here is my code from the table view.
#interface MyPFQueryTableViewController : PFQueryTableViewController <PFLogInViewControllerDelegate, PFSignUpViewControllerDelegate>
#property (nonatomic, strong) NSIndexPath *controlRowIndexPath;
#property (nonatomic, strong) NSIndexPath *tappedIndexPath;
#implementation MyPFQueryTableViewController {
ListItemObject *listDetail;
}
#synthesize controlRowIndexPath;
#synthesize tappedIndexPath;
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
PFObject *object = [self.objects objectAtIndex:indexPath.row];
[object deleteInBackgroundWithBlock:^(BOOL succeeded, NSError *error) {
[self loadObjects];
}];
}
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath object:(PFObject *)object {
static NSString *CellIdentifier = #"listCell";
PFTableViewCell *cell = (PFTableViewCell *)[tableView dequeueReusableCellWithIdentifier:#"listCell"];
if (cell == nil) {
cell = [[PFTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
// Configure the cell
cell.textLabel.text = [object objectForKey:self.textKey];
//cell.imageView.file = [object objectForKey:self.imageKey];
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
[super tableView:tableView didSelectRowAtIndexPath:indexPath];
//if user tapped the same row twice let's start getting rid of the control cell
if([indexPath isEqual:self.tappedIndexPath]){
[tableView deselectRowAtIndexPath:indexPath animated:NO];
}
//update the indexpath if needed... I explain this below
indexPath = [self modelIndexPathforIndexPath:indexPath];
//pointer to delete the control cell
NSIndexPath *indexPathToDelete = self.controlRowIndexPath;
//if in fact I tapped the same row twice lets clear our tapping trackers
if([indexPath isEqual:self.tappedIndexPath]){
self.tappedIndexPath = nil;
self.controlRowIndexPath = nil;
}
//otherwise let's update them appropriately
else{
self.tappedIndexPath = indexPath; //the row the user just tapped.
//Now I set the location of where I need to add the dummy cell
self.controlRowIndexPath = [NSIndexPath indexPathForRow:indexPath.row + 1 inSection:indexPath.section];
}
//all logic is done, lets start updating the table
[tableView beginUpdates];
//lets delete the control cell, either the user tapped the same row twice or tapped another row
if(indexPathToDelete){
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPathToDelete]
withRowAnimation:UITableViewRowAnimationNone];
}
//lets add the new control cell in the right place
if(self.controlRowIndexPath){
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:self.controlRowIndexPath]
withRowAnimation:UITableViewRowAnimationNone];
}
//and we are done...
[tableView endUpdates];
}
- (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath
{
if([indexPath isEqual:self.controlRowIndexPath]){
return 45; //height for control cell
}
return 70; //height for every other cell
}
- (NSIndexPath *)modelIndexPathforIndexPath:(NSIndexPath *)indexPath
{
int whereIsTheControlRow = self.controlRowIndexPath.row;
if(self.controlRowIndexPath != nil && indexPath.row > whereIsTheControlRow)
return [NSIndexPath indexPathForRow:indexPath.row - 1 inSection:0];
return indexPath;
}
#end
The problem is in your didSelectRowAtIndexPath method. You have:
[tableView beginUpdates];
//lets delete the control cell, either the user tapped the same row twice or tapped another row
if(indexPathToDelete){
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPathToDelete]
withRowAnimation:UITableViewRowAnimationNone];
}
//lets add the new control cell in the right place
if(self.controlRowIndexPath){
[self.tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:self.controlRowIndexPath]
withRowAnimation:UITableViewRowAnimationNone];
}
//and we are done...
[tableView endUpdates];
Before you make any calls to tell the table to add or remove any rows, you must update your data source with by adding or removing data. The table will check how many sections and rows there are before and after your add/remove rows. The number of sections and rows after the change must properly reflect how much data you add/remove with how many rows you add/remove.
And of course you must implement the numberOfRowsInSection method.
What does your - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section look like?
This error happens when you try to add or delete a row from the UITableView, but the number of rows that you claim to be in the section after the update in that method is not consistent with the new data that should be loaded.
Ex, if your numberOfRowsInSection always returns 4 and you add a row in that section, the tableView will want it to be 5, but it will not be so it will crash. You need to keep track of how many rows are in each section and return that number.