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];
}
}
Related
I have a UITableView with a simple array as data source. I designed a custom nib for a special UITableViewCell that is shown when the array is empty (i.e. when the app first starts).
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if ([self.wallet count] == 0)
return 1;
else return [self.wallet count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
// If there isn't any coupon yet, then show the custom "No Coupon Yet" cell
if ([self.wallet count] == 0)
return [tableView dequeueReusableCellWithIdentifier:#"NoCouponCell" forIndexPath:indexPath];
else {
CouponCell *cell = [tableView dequeueReusableCellWithIdentifier:#"CouponCell" forIndexPath:indexPath];
Coupon *coupon = [self.wallet objectAtIndex:indexPath.row];
[cell configureForCoupon:coupon];
return cell;
}
}
Since I'd like to add the swipe-to-delete functionality, I provided the following method for the view controller.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
[self.wallet removeObjectAtIndex:indexPath.row];
// Creates a new, temporary array holding just the one index-path item
NSMutableArray *tmp = [[NSMutableArray alloc] initWithObjects:indexPath, nil];
// Tells the table view to delete the row with a nice animation
[tableView deleteRowsAtIndexPaths:tmp withRowAnimation:UITableViewRowAnimationAutomatic];
}
However, when the table view has only one row and I try to delete it, my app crashes. Why?
EDIT: The debug info tells that a NSInternalInconsistencyException is raised.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete)
{
// Delete the row from the data source
[self.wallet removeObjectAtIndex:indexPath.row];
[tableView reloadData]; // reload your table to see updates
// or if you what some animation use|
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
...
Here's a fix for your cellForRowAtIndexPath:
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
CouponCell *cell = [tableView dequeueReusableCellWithIdentifier:[self.wallet count] == 0 ? #"NoCouponCell" : #"CouponCell" forIndexPath:indexPath];
if ([self.wallet count] > 0)
{
Coupon *coupon = [self.wallet objectAtIndex:indexPath.row];
[cell configureForCoupon:coupon];
}
return cell;
}
try this in your code:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [self.wallet count];
}
You are returning a rowcount of 1 if your data array wallet has no elements:
if ([self.wallet count] == 0)
return 1;
else return [self.wallet count];
But in the commitEditingStyle method you don't handle this case: This means that it's possible to delete the NoCouponCell. And I assume that the crash occurs, because you want to remove an object from your data-array which does not exist.
[self.wallet removeObjectAtIndex:indexPath.row];
Solution: Use the following delegate method to determine when a cell can be edited: This prevents the delegate method commitEditingStyle to be called.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath{
return [self.wallet count] > 0
}
Try this piece of code:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
[self.wallet removeObjectAtIndex:indexPath.row];
// Creates a new, temporary array holding just the one index-path item
NSMutableArray *tmp = [[NSMutableArray alloc] initWithObjects:indexPath, nil];
// Tells the table view to delete the row with a nice animation
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:tmp withRowAnimation:UITableViewRowAnimationAutomatic];
[tableView endUpdates];
}
Use this in your numberOfRowsInSection function:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return [self.wallet count];
}
And at the end of your commitEditingStyle function, use
[tableView reloadData];
you can add a view to the UITableview tableFooterView on tableview datasource, you can put your custome cell'content in this view
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
if (dataArray.count == 0) {
UIView *view = [[UITableView alloc] initWithFrame:self.view.bounds];
view.backgroundColor = [UIColor blueColor];
self.tableView.tableFooterView = view;
}
return dataArray.count;
}
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];
Hi I am trying out Xcode and I want to delete items from the list. I can get the delete button to show but once the delete button is clicked it wont delete. The delete code is at the end of the code. There is something missing in the deleting part of the code and I am not really sure what it is.
#import "ToDoListTableViewController.h"
#import "ToDoItem.h"
#import "AddToDoItemViewController.h"
#interface ToDoListTableViewController ()
#property NSMutableArray *toDoItems;
#end
#implementation ToDoListTableViewController
- (void)loadInitialData {
ToDoItem *item1 = [[ToDoItem alloc] init];
item1.itemName = #"Buy milk";
[self.toDoItems addObject:item1];
ToDoItem *item2 = [[ToDoItem alloc] init];
item2.itemName = #"Buy eggs";
[self.toDoItems addObject:item2];
ToDoItem *item3 = [[ToDoItem alloc] init];
item3.itemName = #"Read a book";
[self.toDoItems addObject:item3];
}
- (IBAction)unwindToList:(UIStoryboardSegue *)segue {
AddToDoItemViewController *source = [segue sourceViewController];
ToDoItem *item = source.toDoItem;
if (item != nil) {
[self.toDoItems addObject:item];
[self.tableView reloadData];
}
}
- (void)viewDidLoad {
[super viewDidLoad];
self.toDoItems = [[NSMutableArray alloc] init];
[self loadInitialData];
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
#pragma mark - Table view data source
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
// Return the number of sections.
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:
(NSInteger)section {
// Return the number of rows in the section.
return [self.toDoItems count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath: (NSIndexPath *)indexPath {
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:#"ListPrototypeCell" forIndexPath:indexPath];
// Configure the cell...
ToDoItem *toDoItem = [self.toDoItems objectAtIndex:indexPath.row];
cell.textLabel.text = toDoItem.itemName;
if (toDoItem.completed) {
cell.accessoryType = UITableViewCellAccessoryCheckmark;
} else {
cell.accessoryType = UITableViewCellAccessoryNone;
}
return cell;
}
// Override to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
In your tableView:(UITableView *)tableView commitEditingStyle: (UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath method you only delete the cell. You also have to delete your actual data.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete data from array
[self.toDoItems removeObjectAtIndex:indexPath.row];
// Delete the row from the data source
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
When deleteRowsAtIndexPaths gets called it refreshes the tableViews data, which then calls cellForRowAtIndexPath. Now that you didn't change the data, nothing will change in the tableView.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete data from array
[self.toDoItems removeObjectAtIndex:indexPath.row];
// Reload table -> it's OK
[tableView reloadData];
} else if (editingStyle == UITableViewCellEditingStyleInsert) {
// Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
}
}
I am deleting all the items in UITableView. And thus the array from which I am loading the UITableView has count = 0. After deleting the last item in array, on reloading the table, I am getting error at numberofRowInSection.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [arrProjects count];
}
- (void)tableView:(UITableView *)aTableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"");
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[tableProject beginUpdates];
Project *project = [arrProjects objectAtIndex:indexPath.row];
[[CommonModel shared]DeleteProjectDetails:project.ProjectId];
[arrProjects removeObject:project];
[self reloadTableProject:YES];
[tableProject endUpdates];
}
}
-(void) reloadTableProject:(BOOL)isReloadRequired
{
//[arrProjects removeAllObjects];
arrProjects = [[CommonModel shared]GetAllProjects];
if(isReloadRequired)
[tableProject reloadData];
}
This is the error :
'Invalid update: invalid number of rows in section 0. The number of
rows contained in an existing section after the update (1) 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, 0 deleted) and plus or minus the number of
rows moved into or out of that section (0 moved in, 0 moved out).'
I am getting this error every time, not only when the array is empty.
Set :
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return [_datasourceArray count];
}
To empty your TableView, do :
[_datasourceArray removeAllObjects];
[_tableView reloadData];
You need to remove the object from arrProjects too, inside UITableViewCellEditingStyleDelete,
[arrProjects removeObjectAtIndex:indexPath.row];
it is also good to include
[self.tableView beginUpdates] and [self.tableView endUpdates]
when you start and end the removal of these objects
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [arrProjects count];
}
- (void)tableView:(UITableView *)aTableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
NSLog(#"");
if (editingStyle == UITableViewCellEditingStyleDelete)
{
Project *project = [arrProjects objectAtIndex:indexPath.row];
[[CommonModel shared]DeleteProjectDetails:project.ProjectId];
[arrProjects removeObject:project.ProjectId];
[self reloadTableProject: YES];
}
}
I have a thread problem SIGABRT when i try to add one more cell in my app; That is the exception which Xcode gave me:
Invalid update: invalid number of rows in section 0. The number of rows contained in an existing section after the update (0) must be equal to the number of rows contained in that section before the update (0), plus or minus the number of rows inserted or deleted from that section (1 inserted, 0 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).
That is the code where i consider is the problem
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath
{
PlayerCell *cell = (PlayerCell *)[tableView
dequeueReusableCellWithIdentifier:#"PlayerCell"];
Player *player = [self.players objectAtIndex:indexPath.row];
cell.nameLabel.text = player.name;
cell.gameLabel.text = player.game;
cell.ratingImageView.image = [self
imageForRating:player.rating];
return cell;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
[self.players removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade]; }
}
- (NSInteger)tableView:(UITableView *)tableView
numberOfRowsInSection:(NSInteger)section
{
return [self.players count];
}
UPD.
I have an array in AppDelegate to preconfig several cells (to show user, how it looks like) and full it with follow code:
_players = [NSMutableArray arrayWithCapacity:20]; // make an array in appdelegate
Player *player = [[Player alloc] init]; //
player.name = #"Bill Evans"; //
player.game = #"Tic-Tac-Toe"; //Make new player
player.rating = 4; //
[_players addObject:player]; //Add in array in AppDelegate
PlayersViewController *playersViewController = [PlayersViewController new]; //Make instance for main array
playersViewController.players = _players; //add new item from appDelegate array to main
Another piece of code where the mistake may be (it loads when user taps on save button to add new cell)
- (void)playerDetailsViewController:
(PlayerDetailsViewController *)controller
didAddPlayer:(Player *)player
{
[self.players addObject:player];
NSIndexPath *indexPath =
[NSIndexPath indexPathForRow:[self.players count] - 1 inSection:0];
[self.tableView insertRowsAtIndexPaths:
[NSArray arrayWithObject:indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
[self dismissViewControllerAnimated:YES completion:nil];
}
So can anyone tell me, where is my mistake? If needed, i can send further code.
Thanks.