19

I've tried putting this in various parts of my code, like at the end of commitEditingStyle method, but I can't get it to stop editing mode. Basically, I want to automatically exit editing mode when there are no more cells...

if ([self.tableView numberOfRowsInSection:0] ==0)
    {
        NSLog(@"this triggers, but doesn't stop editing..");
        self.tableView.editing = NO;
        [self.tableView endEditing:YES];
    }
cannyboy
  • 24,180
  • 40
  • 146
  • 252

5 Answers5

37

How about [self setEditing:NO animated:YES]? I suppose to self is an instance of UITableViewController.

Sulthan
  • 128,090
  • 22
  • 218
  • 270
AechoLiu
  • 17,522
  • 9
  • 100
  • 118
12

From the apple docs:

Note: The data source should not call setEditing:animated: from within its implementation of tableView:commitEditingStyle:forRowAtIndexPath:. If for some reason it must, it should invoke it after a delay by using the performSelector:withObject:afterDelay: method.

So, calling this within commitEditingStyle is not a great practice.

tooluser
  • 1,481
  • 15
  • 21
5

If is not just [self setEditing:NO animated:YES] ?

Benoît
  • 7,395
  • 2
  • 25
  • 30
1

After playing around with this, here are the things to know: There are separate setEditing routines for the controller and for the tableView. Make sure to use the one for the controller. Also, it needs a delay as noted above. For this, I used Matt’s delay function. As an added bonus, one can disable the Edit button when there are no items in your list. The button becomes enabled again when an item is added. Code is in Swift5.

var someArray: [SomeStruct] = [] {
    didSet {
        if let btn = navigationItem.rightBarButtonItem {
            if someArray.count > 0 {
                btn.isEnabled = true
            } else {
                btn.isEnabled = false   // Needs to respond immediately - don't put in delay
                closeDownEditMode()
            }
        }
    }
}

func delay(_ delay:Double, closure:@escaping ()->()) {
    let when = DispatchTime.now() + delay
    DispatchQueue.main.asyncAfter(deadline: when, execute: closure)
}

func closeDownEditMode() {
    delay(0.1) { [weak self] in
        self?.setEditing(false, animated: true)
    }
}
anorskdev
  • 1,867
  • 1
  • 15
  • 18
0

As mentioned by tooluser the docu states that setEditing:animated: should not be called from within tableView:commitEditingStyle:forRowAtIndexPath:. This is still the case in 2023.

However, a solution to make it work is inspired by this post to use performBatchUpdates:completion:.

Working example in iOS 15:

- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
   if (editingStyle == UITableViewCellEditingStyleDelete) {
        // Delete the row from the data source:
        [_myData removeObjectAtIndex:indexPath.row];

        // Update table view:
        [tableView performBatchUpdates:^{
            // Delete the row:
            [tableView deleteRowsAtIndexPaths:@[indexPaths]
                             withRowAnimation:UITableViewRowAnimationFade];
        } completion:^(BOOL finished) {
            // Disable Edit mode if there is no more data (after deleting the last row):
            if ([self->_myData count] == 0) {
                [tableView setEditing:NO
                             animated:NO];
            }
        }];
   }
}
Martijn
  • 429
  • 4
  • 13