UITableView deletion not working - iphone

I am trying to delete a row from a UITableView.
My UITableView is populated from a NSMutableArray named TableData.
When I am deleting a row and reloading the tableview, it shows that the last row has been removed [not the selected row].
But when I NSLog() the contents of the mutable array it shows that the selected row has been removed.
This is my code:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[TableData removeObjectAtIndex:indexPath.row];
[tableView reloadData];
for (int i = 0; i < [TableData count]; i++)
{
NSLog(#"Value at %d :%#", i, [TableData objectAtIndex:indexPath.row]);
}
}
}

Don't call reloadData instead, call [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:YES];.

Related

No update or numberOfRowsInSection after delete with commitEditingStyle

My table doesn't update after removing an item with Edit / Delete or the swipe-delete gesture. If I do Edit / Delete, the Delete button doesn't disappear. It stays there in a pressed/stuck state. When I then click Done, the Delete button goes away. A screenshot of this is attached at the bottom of this post.
My numberOfRowsInSection code is executed when the app is started, but not after the deletion of an item.
I'm using a UITableViewController. The definition in my .h file:
#interface BNVFavoritesTableViewController : UITableViewController <UITableViewDelegate, UITableViewDataSource>{
BNVAppDelegate *appDelegate;
IBOutlet UITableView *myTable;
}
#property (retain, nonatomic) IBOutlet UITableView *myTable;
#end
Here's the relevant code from my .m file:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
return 1;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
NSLog(#"number of rows:\t%d", [appDelegate.favoritesArray count]);
return [appDelegate.favoritesArray count];
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
}
//Get the object from the array.
BNVFavorite *favoriteObj = [appDelegate.favoritesArray objectAtIndex:indexPath.row];
//Set the name.
cell.textLabel.text = favoriteObj.name;
// Set up the cell
return cell;
}
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
// If row is deleted, remove it from the list.
if (editingStyle == UITableViewCellEditingStyleDelete){
NSLog(#"before delete\t%d", [appDelegate.favoritesArray count]);
BNVFavorite *selectedObject = [appDelegate.favoritesArray objectAtIndex:indexPath.row];
NSString *selectedName = selectedObject.name;
// delete from sqlite database
[appDelegate removeFavoriteFromDB:selectedName];
// delete from memory array
[appDelegate.favoritesArray removeObjectAtIndex:indexPath.row];
// delete in user interface
[myTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
NSLog(#"after delete\t%d", [appDelegate.favoritesArray count]);
}
}
When deleting, I see 'before delete' and 'after delete' messages in my log (as expected), but no 'number of rows' messages.
My datasource and delegate outlets from the Table View are connected to the TableViewController class. I also tried doing this in the ViewDidLoad method, but that didn't make a diferent. Forcing a [myTable reloadData]; at the end of my commitEditingStyle is also not helping.
Finally, here's a screenshot of that 'stuck' delete button.
http://i.stack.imgur.com/ukUu0.png
Clicking it a few times causes an NSRangeException/out of bounds error, indicating that the code from commitEditingStyle is executed.
After hours of searching, I found the problem. Turns out the referencing outlet from the tableview in the storyboard to myTable in my controller class didn't exist anymore. I must have removed it accidentally. I found out about it when I noticed the code started working when I replaced myTable with self.tableView.
You need to add your delete animation between beginUpdates and endUpdates.
[myTable beginUpdates];
[myTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[myTable endUpdates];
Just check your connection in connection inspector for your table.
or if it is properly connected then
Reload your table after deleting record
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
// If row is deleted, remove it from the list.
if (editingStyle == UITableViewCellEditingStyleDelete){
NSLog(#"before delete\t%d", [appDelegate.favoritesArray count]);
BNVFavorite *selectedObject = [appDelegate.favoritesArray objectAtIndex:indexPath.row];
NSString *selectedName = selectedObject.name;
// delete from sqlite database
[appDelegate removeFavoriteFromDB:selectedName];
// delete from memory array
[appDelegate.favoritesArray removeObjectAtIndex:indexPath.row];
// delete in user interface
[myTable deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
NSLog(#"after delete\t%d", [appDelegate.favoritesArray count]);
[myTable reloadData];
}
}

How to get selected row from UITableView with Search Display Controller

I have my search display view controller based off TableSearch.
Normally, following expression gives selected index row:
self.tableView.indexPathForSelectedRow.row
However while in search mode, selected row can be obtained using:
self.searchDisplayController.searchResultsTableView.indexPathForSelectedRow.row
I use the above indices to remove respective rows (from my back end arrays) soon after some processing - at the end of didSelectRowAtIndexPath. The arrays I use are listContent and filteredListContent - as per the Apple example.
My issue is, while in search mode, I remove a row using:
[self.filteredListContent removeObjectAtIndex: self.searchDisplayController.searchResultsTableView.indexPathForSelectedRow.row]
However, at the same time, I also want to remove the same object from self.listContent because when I return to non-search mode, that row should not appear.
I saw that self.tableView.indexPathForSelectedRow.row does not update regularly while in search results view. Instead, it gives the last selected row before I entered the search results view.
Off course, I can put some content into my array objects so that both indexes can be cross-referenced. But is there any efficient solution other than that? I think table view should have this mechanism.
And yes, I already do following in my viewWillAppear:
[self.tableView deselectRowAtIndexPath:self.tableView.indexPathForSelectedRow animated:YES];
This is working fine for me...
#pragma mark - delete row
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
if(tableView == self.searchDisplayController.searchResultsTableView)
// searching mode
{
// find row (index) from listContent
arrayObject = [filteredlistContent objectAtIndex:indexPath.row];
NSUInteger fooIndex = [listContent indexOfObject: arrayObject];
NSLog(#"index listContent %u", fooIndex);
//remove from listContent
[self.listContent removeObjectAtIndex:fooIndex];
[self.tableView reloadData];
//remove from filteredlistContent
[self.filteredlistContent removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
else // tableView mode
{
[self.listContent removeObjectAtIndex:indexPath.row];
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
}

problem with commitEditingStyle -to delete cell in the table

i have one section table which contain the section and i want to delete the perticular cell swap and delete this cell and remove that cell from table and also remove from the array.
and how to animate that when the delete the cell.
for that i code below but which is not working please help to do this.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[self.reports removeObjectAtIndex:indexPath.row];
[tbl reloadData];
[tbl deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
}
}
After much more R&D then i build up new code and which is successfully Run
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[[[self.reports objectAtIndex:indexPath.section] valueForKey:#"events"] removeObjectAtIndex:indexPath.row];
[tbl deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:indexPath.row inSection:indexPath.section]] withRowAnimation:UITableViewRowAnimationLeft];
[NSTimer scheduledTimerWithTimeInterval: 0.1 target: self selector: #selector(tableReload) userInfo: nil repeats: NO];
}
}
-(void)tableReload{
[tbl reloadData]; }
Firstly you should not Reload table before deleting row from table. Secondly, in your case you have multiple sections and multiple rows in that section, I guess. So, your
[tbl deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
won't work.
Deleting object from array will work. You don't have to delete row from your table. Just reload table :
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
[self.reports removeObjectAtIndex:indexPath.row];
[tbl reloadData];
}
But do take care that you are putting the correct indexNumber.
You are not nil terminating your NSArray and that is why the row isn't being deleted from your Table View.
The following line:
[tbl deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath]
withRowAnimation:UITableViewRowAnimationFade];
Should actually be:
[tbl deleteRowsAtIndexPaths:[NSArray arrayWithObjects:indexPath, nil]
withRowAnimation:UITableViewRowAnimationFade];
Notice the nil after IndexPath. arrayWithObjects should be a nil terminated list of Objects

UITableView and numberOfRowsInSection crash

I have a problem when trying to delete rows from my UITableView:
The UITableView gets the number of rows from NSMutableArray:
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
return [alertsArray count];
}
I add objects to the NSMutableArray in this way:
- (void)saveButton:(id)sender {
[alertsArray addObject:
[self.tableView reloadData];
}
With this code I allow to delete rows:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source.
[self.tableView deleteRowsAtIndexPaths:[NSMutableArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[alertsArray removeObjectAtIndex:indexPath.row];
[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.
}
}
From some reason, when trying to delete rows, the application crashes.
Thanks!
You should only do
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source.
[alertsArray removeObjectAtIndex:indexPath.row];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
That is, correct your model first, and then call deleteRowsAtIndexPaths:
You will find the appropriate error message in the console window, BTW.
Also, in general no need to use reloadData here, when you didn't change other things as well.

Inserting and deleting UITableViewCell at the same time not working

I'm having quite a bit of pain inserting and deleting UITableViewCells from the same UITableView!
I don't normally post code, but I thought this was the best way of showing where I'm having the problem:
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
return 5;
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
if (iSelectedSection == section) return 5;
return 1;
}
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
//NSLog(#"drawing row:%d section:%d", [indexPath row], [indexPath section]);
static NSString *CellIdentifier = #"Cell";
UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
if (cell == nil) {
cell = [[[UITableViewCell alloc] initWithFrame:CGRectZero reuseIdentifier:CellIdentifier] autorelease];
}
if (iSelectedSection == [indexPath section]) {
cell.textColor = [UIColor redColor];
} else {
cell.textColor = [UIColor blackColor];
}
cell.text = [NSString stringWithFormat:#"Section: %d Row: %d", [indexPath section], [indexPath row]];
// Set up the cell
return cell;
}
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// Navigation logic -- create and push a new view controller
if ([indexPath row] == 0) {
NSMutableArray *rowsToRemove = [NSMutableArray array];
NSMutableArray *rowsToAdd = [NSMutableArray array];
for(int i=0; i<5; i++) {
//NSLog(#"Adding row:%d section:%d ", i, [indexPath section]);
//NSLog(#"Removing row:%d section:%d ", i, iSelectedSection);
[rowsToAdd addObject:[NSIndexPath indexPathForRow:i inSection:[indexPath section]]];
[rowsToRemove addObject:[NSIndexPath indexPathForRow:i inSection:iSelectedSection]];
}
iSelectedSection = [indexPath section];
[tableView beginUpdates];
[tableView deleteRowsAtIndexPaths:rowsToRemove withRowAnimation:YES];
[tableView insertRowsAtIndexPaths:rowsToAdd withRowAnimation:YES];
[tableView endUpdates];
}
}
This code creates 5 sections, the 1st (indexed from 0) with 5 rows. When you select a section - it removes the rows from the section you had previously selected and adds rows to the section you just selected.
Pictorally, when I load up the app, I have something like this:
http://www.freeimagehosting.net/uploads/1b9f2d57e7.png http://www.freeimagehosting.net/uploads/1b9f2d57e7.png
Image here: http://www.freeimagehosting.net/uploads/1b9f2d57e7.png
After selecting a table row 0 of section 2, I then delete the rows of section 1 (which is selected by default) and add the rows of section 2. But I get this:
http://www.freeimagehosting.net/uploads/6d5d904e84.png http://www.freeimagehosting.net/uploads/6d5d904e84.png
Image here: http://www.freeimagehosting.net/uploads/6d5d904e84.png
...which isn't what I expect to happen! It seems like the first row of section 2 somehow remains - even though it definitly gets deleted.
If I just do a [tableView reloadData], everything appears as normal... but I obviously forefit the nice animations.
I'd really appreciate it if someone could shine some light here! It's driving me a little crazy!
Thanks again,
Nick.
Struggled to get this to work. Here's my code to add a row to my tableView:
NSIndexPath *indexPath = [NSIndexPath indexPathForRow:0 inSection:0];
[tableView beginUpdates];
[dataSource insertObject:[artistField text] atIndex:0];
[tableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];
[tableView endUpdates];
I seem to remember that numberOfRowsInSection: will get called when you call deleteRows or insertRow, you need to be really careful that the reality numberOfRowsInSection cliams matches your changes. In this case you may want to try moving the iSelectedSection = [indexPath section]; line to after the endUpdates.
I don't remember where I read this but I believe you shouldn't perform table row updates (insertions and deletions) from inside one of the table view delegate functions. I think a better alternative would be to do a performSelectorOnMainThread passing along the necessary information needed to perform the updates as an object. Something like:
- (void)tableView:(UITableView *)tableView
didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
// ....
[self performSelectorOnMainThread: #selector(insertRows:)
withObject: someObjectOrNil]; // double check args
}
- (void) insertRows: (NSObject*)someObjectOrNil {
[tableView beginUpdates];
// update logic
[tableView endUpdates];
// don't call reloadData here, but ensure that data returned from the
// table view delegate functions are in sync
}
In the code you posted, your loop index runs from 0 to 4, which suggests that it would delete all of the rows in section 1, and then add five new rows to section 2. Since each section already has a row 0, this would add a second instance of section 2, row 0 to the table.
I would suggest having your loop run from 1 to 4:
for (int i=1; i<5; i++)
{
// ...
}
FYI: This bug seems to have been fixed completely with the 2.2 iPhone update.
Thanks Apple!
Nick.