I have a UITableViewCell and configured it that editing is enabled.
Everything works fine but my problem is that the delete confirmation doesn't disappear when the round delete button (the circle with a "|") is pressed the second time.
Does anybody know why this could happen?
[EDIT]
I narrowed it down to a method which is called every second and in that method I call beginUpdates and endUpdates on the editable UITableView. Does anybody knows a workaround?
If I had to take a stab in the dark... You probably are setting editing to true and then not setting it back to false. Make sure whatever method you call to set the value of editing reverses its value each time it's called.
- (void)setTableDelete
{
bool temp = !myTableView.editing;
[myTableView setEditing:temp animated:YES];
}
Try adding something like this:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
Dashboard *dashboard = [dashboards dashboardAtIndex:indexPath.row];
if (editingStyle == UITableViewCellEditingStyleDelete) {
// Delete the row from the data source
NSLog(#"delete");
} 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
NSLog(#"insert");
}
[self.tableView reloadRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationNone];
}
Reloading the rows is key.
Solved it by avoiding the use of beginUpdates & endUpdates methods if tableView is in edit mode, instead i update the cells manually if edit mode is YES.
Related
I am trying to delete a cell and remove a section from a UITableView with the following code:
[self.tableView beginUpdates];
[arraymasterFeedFullDetails removeObjectAtIndex:cellSelectedIndexPath.section];
[self.tableView deleteSections:[NSIndexSet indexSetWithIndex:cellSelectedIndexPath.section]withRowAnimation:UITableViewRowAnimationFade];
[self.tableView endUpdates];
Here,cellSelectedIndexPath is NSIndexPath variable which is pointing to the section is currently selected. arraymasterFeedFullDetails is my datasource and only one row per each section.
- (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView
{
// Return the number of sections.
return [arraymasterFeedFullDetails count];
}
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
return 1;
}
When you have a data source(arraymasterFeedFullDetails in your case), the thing you need to do to delete an item, is to remove object from data source and then reload the table.
You can reload the table using [self.tableView reloadData];
So your code would be like this:
[arraymasterFeedFullDetails removeObjectAtIndex:cellSelectedIndexPath.section];
[self.tableView reloadData];
When you have a data source(arraymasterFeedFullDetails in your case), the thing you need to do to delete an item, is to remove object from data source and then either reload the whole table, or, remove the cells from the datasource with animation.
This in general will produce a visually better result.
The reloadData method will reload the whole table, without animation.
Currently shown cells will be simply redrawn. E.g.:
[self.tableView reloadData];
You won't need to update the tableview itself, as this will be simply redrawn.
In order to remove just "edited away cells", with an animation effect, you can use the method deleteRowsAtIndexPaths: withRowAnimation:
E.g.:
// Overridden to support editing the table view.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[_list2 removeObjectAtIndex:indexPath.row]; // remove row from array
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade]; // remove cell from UITableView
} 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
}
}
You could also remove rows from your mutable array, then call
deleteSections:withRowAnimation:
between beginUpdates and endUpdates in order to delete a whole section from your tableview;
In both animated deletion approaches, you will need to make sure that the data source has the same count of the tableview cells (after the deletions) before doing any animation which will update the tableview.
I'm using a UISegmentedControl to switch a UITableView between two datasets (think favorites and recents). Tapping the segmented control reloads the tableview with the different data set.
[self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:anim];
When the user swipes to delete a row it works fine. HOWEVER when the user switches datasets via the segmented control, the DELETED CELL gets re-used without altering it's appearance (i.e. the red 'DELETE' button is still there and the row content is nowhere to be seen). This appears to be the opposite problem that most people are seeing which is the delete button not appearing.
This is the delete code:
- (UITableViewCellEditingStyle) tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
return UITableViewCellEditingStyleDelete;
}
- (void) tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if (editingStyle == UITableViewCellEditingStyleDelete)
{
if ([self.current isEqualTo:self.favorites])
{
Favorite *fav = self.favorites[indexPath.row];
NSMutableArray *mut = [self.favorites mutableCopy];
[mut removeObjectAtIndex:indexPath.row];
self.favorites = mut;
self.current = self.favorites;
[self.tableView deleteRowsAtIndexPaths:#[indexPath]
withRowAnimation:UITableViewRowAnimationAutomatic];
}
}
}
The tableview is set to single select, and self.tableView.editing == NO. I have also tried using [self.tableView reloadData] and deleting/inserting the difference in rows from one dataset to the next. Neither works.
The UITableViewCell I'm using supplies no backgroundView or selectedBackgroundView
[EDIT]
Segmented Control Value Changed:
- (IBAction)modeChanged:(id)sender
{
if (self.listMode.selectedSegmentIndex == 1)
{
self.current = self.favorites;
}
else
{
self.current = self.recents;
}
// Tryin this:
[self.tableView reloadData];
// Tried this:
// [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];
}
// Only 1 Section per table
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section;
{
return [self.current count];
}
Oh for the love of...
I wasn't calling [super prepareForReuse]; in my UITableViewCell subclass.
UGH.
I ran into the same thing: to "delete" a custom UITableViewCell, I was removing it from the table and putting it onto another list, which the user could then display in a modal view when they have regrets and want to put it back. In iOS7 (but not iOS6), the cells so moved had the big ugly "DELETE" button still on them, despite calling setEditing:NO and so on. (And in addition, the rest of the cell content was not drawn at all, even though inspecting the cells in the debugger showed that all the subpanes were still there.)
Unlike Stephen above, I hadn't overridden prepareForReuse, so that wasn't the problem. But it was related: in my case, the cells weren't created with a reuse identifier:
self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:nil];
And per the docs, "If the cell object does not have an associated reuse identifier, this method is not called." But apparently, in iOS7 at least, it should be.
So the solution, in my case, was to explicitly call this [cell prepareForReuse] on each cell as I loaded it into the new table.
I want to delete a row from my tableview. I cannot find a solution that works from the other simialr questions here.
I know I need to use the following code, But I cant seem to figure out how to properly finish this line of code to make it work.
[dailyIncomeArray removeObjectAtIndex:indexPath.row];
But what goes where is says "dailyIncomeArray"?
[what-goes-here removeObjectAtIndex:indexPath.row];
I have a getData method that populates my tableview. Next I want to be able to swipe to the left and hit that red delete button. Thanks in advance for your help!
Heres the rest of the method
// 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
[dailyIncomeArray removeObjectAtIndex:indexPath.row];
[self.tableView reloadData];
//[tableView deleteRowsAtIndexPaths:[NSMutableArray arrayWithObject:results] 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
}
}
Here's the error I'm receiving. I don't understand what this means.
No visible #interface for 'NSArray' declares the selector 'removeObjectAtIndex:'
I'm using the "swipe-to-delete" functionality in my UITableView. It worked without problems in the past.
Since I updated my project to iOS7, the cell does not exit the "swiped" state. So when I click the delete button, -tableView:commitEditingStyle:forRowAtIndexPath: gets called, but it does not hide the button again.
Do I need to do that manually since iOS7? If yes, what method do I have to use?
I'm having same problem. The problem is the delegate method tableView:didEndEditingRowAtIndexPath: it isn't more called (don't know why).
the way that I found is call the [tableview reloadData] inside of tableView:commitEditingStyle:forRowAtIndexPath: instead of in tableView:didEndEditingRowAtIndexPath: . This works in iOS 6 and 7.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
[myDataSource removeObjectAtIndex:indexPath.row];
[myTable reloadData];
}
}
I am using the standard table view datasource protocol to delete table cells:
-(void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
if(editingStyle == UITableViewCellEditingStyleDelete)
{
[tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
I would like to run some other code once the animation is completed but the deleteRowsAtIndexPaths:withRowAnimation method does not have a completion block. How else would I run some code after this method completes?
For iOS 6 Apple added - tableView:didEndDisplayingCell:forRowAtIndexPath: to UITableViewDelegate. You should be able to use it to get a callback immediately when each UITableViewCell has been removed from the display, so if you know you've started a deletion animation on a particular index path then you can use it as a usually reliable means of knowing that the animation has ended.
(aside: I guess if the user scrolled the cell off screen during its animation then you could get a false positive, but such things are going to be so unlikely that I'd be likely to add a basic guard against persistent negative consequences and not worry about the ephemeral ones, such as if I end up showing an empty cell when the mid-deletion object is scrolled back onto screen because I already removed it from my store)
I believe one way to do this is to implement UITableViewDataSource's method tableView:commitEditingStyle:forRowAtIndexPath: and execute a delayed performance method there inside.
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (UITableViewCellEditingStyleDelete == editingStyle) {
[self performSelector:#selector(delayedMethod) withObject:nil afterDelay:0.1];
}
}
-(void)delayedMehtod {
// Your code here...
}
It may not be as pretty as a "completion" block but I'm sure it would do the trick.
Hope this helps!