75

I have a UIViewController that implements TableViews delegate and datasource protocols. Now I want to add "swipe to delete" gesture to cells.

How should I go about it.

I have given a blank implementation of commitEditingStyle method and also set the Editing property to YES.

Still the swipe feature is not coming .

Now Do I need to separately add UISwipeGesture to each cell ?

Or am I missing something ?

KlimczakM
  • 11,178
  • 10
  • 55
  • 76
Amogh Talpallikar
  • 11,754
  • 12
  • 71
  • 131
  • Refer the link, it may help you, http://stackoverflow.com/questions/3309484/uitableviewcell-show-delete-button-on-swipe – Sharme Jan 24 '12 at 07:08
  • 2
    I have overridden commitEditingStyle and set Editing to YES and also NOW I have overridden CanEditRowAtIndexPath as well. Normal Edit controls come on which on clicking delete button appears. But not on swiping! Is it because My class is a subclass of UIViewController and only implements the delegate and datasource methods but not of UITableViewController which might be doing something to enable a swipe gesture. – Amogh Talpallikar Jan 24 '12 at 07:18
  • I just set up a UITableView as an IBOutlet in a UIViewController yesterday, and following exactly like that post I showed, I have swipe to delete. So I can say you don't need to enable swipe gestures, though if you really can't get it working any other way, you might have to resort to that. – gurooj Jan 24 '12 at 17:42
  • btw the problem was solved, I had actually overridden editingStyleForRowAtIndexPath and it was returning None when table wasn't in editing mode and thats what the problem was. I added that method for something I was doing previously but forgot to remove it when the requirement changed. – Amogh Talpallikar Jan 25 '12 at 04:59
  • Swift 4 : https://iosdevcenters.blogspot.com/2018/01/table-swipe-actions-in-swift-4-using.html – Bhadresh May 14 '18 at 02:58

13 Answers13

61

As Dan has commented above, you need to implement the following table view delegate methods:

  1. tableView:canEditRowAtIndexPath:
  2. tableView:commitEditingStyle:forRowAtIndexPath:

Note: I have tried this in iOS 6 and iOS 7.

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Return YES - we will be able to delete all rows
    return YES;
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Perform the real delete action here. Note: you may need to check editing style
    //   if you do not perform delete only.
    NSLog(@"Deleted row.");
}
Community
  • 1
  • 1
Dj S
  • 9,992
  • 1
  • 18
  • 24
  • 3
    I just tested this in iOS 8.1.2 on an iPhone 6 and it works. I only needed to implement the `- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath` method as editing should be YES by default. – Kramer Jan 16 '15 at 21:47
55

You don't have to set editing:YES if you need to show Delete button on cell swipe. You have to implement tableView:canEditRowAtIndexPath: and return YES from there for rows you need to edit/delete. This is not necessary when your tableView's dataSource is a subclass of UITableViewContoller - this method, if not overridden, returns YES by default. In all other cases you have to implement it.

EDIT: Together we have found the problem - tableView:editingStyleForRowAtIndexPath: returned UITableViewCellEditingStyleNone if table wasn't in editing mode.

Kyr Dunenkoff
  • 8,050
  • 3
  • 20
  • 21
  • Did you remove `[tableView setEditing:YES];`? – Kyr Dunenkoff Jan 24 '12 at 07:21
  • If I remove it, the basic delete button doesn't come at all ! – Amogh Talpallikar Jan 24 '12 at 07:23
  • 3
    If you don't remove it, you put your table into editing state where swipes don't work. It's either round red minus button on the left or swipes, not together. – Kyr Dunenkoff Jan 24 '12 at 07:24
  • My delete button appears when I click on that edit button on each cell on left hand side when setEditing is true but nothing happens when swipe. – Amogh Talpallikar Jan 24 '12 at 07:25
  • For the third time - remove `setEditing:YES` **AND** implement `canEditRowAtIndexPath` to have what you need. – Kyr Dunenkoff Jan 24 '12 at 07:27
  • 1
    now I have removed setEditing statement but nothing is happening when I swipe. Is it because I am using a UIViewController and not a TabelViewController which might be adding swipe gestures to each cell by default. – Amogh Talpallikar Jan 24 '12 at 07:29
  • let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/6985/discussion-between-amogh-talpallikar-and-kyr-dunenkoff) – Amogh Talpallikar Jan 24 '12 at 07:30
  • 5
    I want to add that `tableView:canEditRowAtIndexPath:` may not be enough. You also have to implement `tableView:commitEditingStyle:forRowAtIndexPath`. – dwlz May 31 '13 at 21:30
  • It is hiding my text when I swipe. Can we change that behaviour? – Durgaprasad Sep 30 '14 at 04:59
  • you should remove this method. ```objc - (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath; ``` – Hugo Jun 16 '15 at 07:42
25
// Override to support conditional editing of the table view.
- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    // Return NO if you do not want the specified item to be editable.
    return YES;
}



// 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
    }   
}
Can Aksoy
  • 1,252
  • 1
  • 11
  • 17
  • 6
    Noteworthy / comment for newbies like me: the row still needs to be deleted, as well as the datasource (e.g. array) needs to be reduced. – BananaAcid Apr 03 '14 at 12:04
12

Please try this code in swift,

override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
   // let the controller to know that able to edit tableView's row 
   return true
}

override func tableView(tableView: UITableView, commitEditingStyle editingStyle UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath)  {
   // if you want to apply with iOS 8 or earlier version you must add this function too. (just left in blank code)
}

override func tableView(tableView: UITableView, editActionsForRowAtIndexPath indexPath: NSIndexPath) -> [UITableViewRowAction]?  {
   // add the action button you want to show when swiping on tableView's cell , in this case add the delete button.
   let deleteAction = UITableViewRowAction(style: .Default, title: "Delete", handler: { (action , indexPath) -> Void in

   // Your delete code here.....
   .........
   .........
   })

   // You can set its properties like normal button
   deleteAction.backgroundColor = UIColor.redColor()

   return [deleteAction]
}
Crashalot
  • 31,452
  • 56
  • 235
  • 393
Masa S-AiYa
  • 610
  • 5
  • 13
5

Try adding the following to your class:

// Override to support conditional editing of the table view.
- (BOOL) tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath
{
    return(YES);
}
David M. Syzdek
  • 14,176
  • 6
  • 27
  • 39
  • 5
    not working for me :( Is it because my class is a subclass of UIViewController and I need to do something extra which UITabelViewController does ? – Amogh Talpallikar Jan 24 '12 at 07:19
  • 1
    @AmoghTalpallikar, How did You solve your problem? Could you post your solution? I also have the same issue. Also my class is a subclass of UIViewController, and all cells' of my tableView are subclass of UITableViewCell. – Shamsiddin Dec 06 '13 at 11:39
3

Conclusion of Kyr Dunenkoff chat is

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {

}

should not be defined if you need delete button to appear on swipe.

Community
  • 1
  • 1
Thiru
  • 1,282
  • 13
  • 20
1

If you are using an NSFetchedResultsControllerDelegate to populate the table view, this worked for me:

  • Make sure tableView:canEditRowAtIndexPath returns true always
  • In your tableView:commitEditingStyle:forRowAtIndexPath implementation, do not delete the row directly from the table view. Instead, delete it using your managed object context, e.g.:

    if editingStyle == UITableViewCellEditingStyle.Delete {
        let word = self.fetchedResultsController.objectAtIndexPath(indexPath) as! Word
        self.managedObjectContext.deleteObject(word)
        self.saveManagedObjectContext()
    }
    
    func saveManagedObjectContext() {
        do {
            try self.managedObjectContext.save()
        } catch {
            let saveError = error as NSError
            print("\(saveError), \(saveError.userInfo)")
        }
    }
    
Steve Liddle
  • 3,595
  • 3
  • 25
  • 38
GabeV
  • 728
  • 6
  • 17
0

This was a problem for me too...I could only get swiping to delete to work once every 10 or so attempts. It turns out the gesture on the TV was being blocked by another gesture in the parent view controller. The TV was nested in a MMDrawerController (swipe able drawer layout).

Just configuring the gesture recognizer in the drawer controller to not respond to close gestures in the flanking drawers allowed swipe to delete to work in my TV.

You could also try doing something like this with the gesture delegate:

-(BOOL)gestureRecognizer:(UIGestureRecognizer *)gestureRecognizer shouldRecognizeSimultaneouslyWithGestureRecognizer:(UIGestureRecognizer *)otherGestureRecognizer {
    return YES;
}
Rajat
  • 1,383
  • 12
  • 23
Kevin
  • 1,779
  • 15
  • 23
  • I know this is old, but I'm having the same exact problem with MMDrawerController.. Could you elaborate on "configuring the gesture recognizer in the drawer controller to not respond to close gestures in the flanking drawers allowed swipe to delete to work in my TV". How do you do that? – Mark Sep 24 '17 at 13:38
0

This is the swift version

// Override to support conditional editing of the table view.
override func tableView(tableView: UITableView, canEditRowAtIndexPath indexPath: NSIndexPath) -> Bool {
    // Return NO if you do not want the specified item to be editable.
    return true
}

// Override to support editing the table view.
override func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
    if editingStyle == .Delete {
        // Delete the row from the data source
        tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
    } else if editingStyle == .Insert {
        // Create a new instance of the appropriate class, insert it into the array, and add a new row to the table view
    }    
}
JZAU
  • 3,362
  • 27
  • 34
0

In my experience, seems like you must have editing on UITableView set to NO for swiping to work.

self.tableView.editing = NO;

kgaidis
  • 10,753
  • 4
  • 58
  • 76
0

After iOS 8.0, you can custom you action in

- (nullable NSArray<UITableViewRowAction *> *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath
user501836
  • 962
  • 1
  • 10
  • 18
-1
NSMutableArray *post= [NSMutableArray alloc]initWithObject:@"1",@"2",@"3",nil]; 


- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView 
           editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath {

    NSUInteger row = [indexPath row];
    NSUInteger count = [posts count];

    if (row < count) {
        return UITableViewCellEditingStyleDelete;
    } else {
        return UITableViewCellEditingStyleNone;
    }
}

- (void)tableView:(UITableView *)tableView 
                    commitEditingStyle:(UITableViewCellEditingStyle)editingStyle
                    forRowAtIndexPath:(NSIndexPath *)indexPath {

    NSUInteger row = [indexPath row];
    NSUInteger count = [posts count];

    if (row < count) {

        [posts removeObjectAtIndex:row];
    }
}
Rajesh
  • 9,724
  • 14
  • 37
  • 58
Vimal Raval
  • 29
  • 1
  • 1
  • 3
-2

You can see all necessary methods by creating a UITableViewController class (temporary) in XCode 5 and then copy which method you would like to use. Those methods you need will be commented out with pre-filled in lines you desire.

Emin Bugra Saral
  • 3,567
  • 1
  • 14
  • 24