UITableViewCell Action Swiping in iOS8 and Swift

Mail.app in iOS7 brought swiping cells to the inbox. The iOS8 beta added a 3rd button to it.  Apple has also introduced an API to assist with creating this effect: UITableViewRowAction. Prior to this, I used SWTableViewCell.

14870105002 77af4bf515 b

Below is how to get the basic functionality working. Please note that you have to implement the 2nd function whether it has a body or not

class TIMUITableViewDelegate: NSObject, UITableViewDelegate {
    func tableView(tableView: UITableView!, editActionsForRowAtIndexPath indexPath: NSIndexPath!) -> [AnyObject]! {
        var shareAction = UITableViewRowAction(style: .Normal, title: "Share") { (action, indexPath) -> Void in
            tableView.editing = false
            println("shareAction")
        }
        shareAction.backgroundColor = UIColor.grayColor()
        
        var doneAction = UITableViewRowAction(style: .Default, title: "Done") { (action, indexPath) -> Void in
            tableView.editing = false
            println("readAction")
        }
        doneAction.backgroundColor = UIColor.greenColor()
        
        var deleteAction = UITableViewRowAction(style: .Default, title: "Delete") { (action, indexPath) -> Void in
            tableView.editing = false
            println("deleteAction")
        }
        
        return [deleteAction, doneAction, shareAction]
    }
    
    func tableView(tableView: UITableView!, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath!) {
    }

}

I can’t get the (-) delete indicator to appear when I put the table into edit mode though. Setting UITableViewCell.shouldIndentWhileEditing = NO is supposed to disable this effect. I’ve tried setting it in 3 places:

I’ve had to add some workarounds to deal with this for now.  I’ve filed rdar://17969970 against this. For now, this is how I’m handling by checking if I’m already in edit mode when I build out the actions array. This isn’t ideal at all. I don’t even want to be able to delete when I’m in edit mode, just reorder. Apologies for switching back to obj-c. The delegate I’m working in is older.

- (void) endEditing
{
    self.editMode = NO;
    self.editControlButton.title = @"Reorder";
    [self setEditing:NO animated:YES];
    //[self.tableView reloadData];
}

- (void) startEditing
{
    self.editMode = YES;
    self.editControlButton.title = @"Done";
    [self.tableView setEditing:YES animated:YES];
}

#pragma - mark UITableViewDelegate

- (BOOL)tableView:(UITableView *)tableView canEditRowAtIndexPath:(NSIndexPath *)indexPath {
    return YES;
}

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
    return UITableViewCellEditingStyleDelete;
}

- (BOOL)tableView:(UITableView *)tableview shouldIndentWhileEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
    NSLog(@"shouldIndentWhileEditingRowAtIndexPath");
    return NO;
}

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath {
    TCORead *item = [self.fetchedResultsControllerDataSource selectedItem];
    manager.currentRead = item;
}

- (NSArray *)tableView:(UITableView *)tableView editActionsForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewRowAction *deleteAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@"Delete" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){
        [self.tableView setEditing:NO];
    }];
    
    //workaround, rdar://17969970
    //normally don't want to be able to get into this menu when reordering
    if (!self.editMode) {
        UITableViewRowAction *shareAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleNormal title:@"Share" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){
            [self.tableView setEditing:NO];
        }];
        shareAction.backgroundColor = [UIColor grayColor];
        
        UITableViewRowAction *doneAction = [UITableViewRowAction rowActionWithStyle:UITableViewRowActionStyleDestructive title:@"Done" handler:^(UITableViewRowAction *action, NSIndexPath *indexPath){
            [self.tableView setEditing:NO];
        }];
        doneAction.backgroundColor = [UIColor greenColor];
        
        [self startEditing];
        return @[deleteAction, doneAction, shareAction];
    }
    
    return @[deleteAction];
}

- (void)tableView:(UITableView *)tableView didEndEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self endEditing];
}

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
    //empty on purpose
}

This post and the Radar helped me collect my thoughts to post on Stack. I’ve been afraid of backlash or Noob. Time to get over it.

Update 2014-09-11

Vanyas has a great sample application that addresses what I’m trying to do.  I was forcing the delete button on the right hand side myself.  Updating editingStyleForRowAtIndexPath to the below fixed my issue:

- (UITableViewCellEditingStyle)tableView:(UITableView *)tableView editingStyleForRowAtIndexPath:(NSIndexPath *)indexPath
{
    //return UITableViewCellEditingStyleDelete;
    return tableView.isEditing ? UITableViewCellEditingStyleNone: UITableViewCellEditingStyleDelete;
}