Search code examples
iosxcodeuitableviewcell

Try to delete UITableViewCell


I create a table view and everything work's fine. I want always display 1 cell in my table view with title "You should add cell". Then when I add information to my array (tableData) I need to display this information in my custom cell. Then when I delete this cell I need to display my 1 cell with title "You should add cell". But I can't do this(Please explain me why?)

My code:

- (void)viewDidLoad {
    [super viewDidLoad];

    _tableData = [[NSMutableArray alloc] init];
    [self.tableView setDelegate:self];
    [self.tableView setDataSource:self];

    self.tableData = [NSMutableArray arrayWithArray:[[SOCoreDataManager sharedManager] getAllAims]];

}

- (NSInteger)tableView:(UITableView *)tableView
 numberOfRowsInSection:(NSInteger)section
{

    if ([self.tableData count] == 0) {
        return 1;
    }

    return [self.tableData count];
}

- (UITableViewCell *)tableView:(UITableView *)table
     cellForRowAtIndexPath:(NSIndexPath *)indexPath {

static NSString* cellID = @"cellForMyAims";

if ((int)[self.tableData count] == 0) {
    static NSString* cellIDw = @"Cell";
    UITableViewCell *cellw = [table dequeueReusableCellWithIdentifier:cellIDw];

    if (!cellw) {
        cellw = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:cellIDw];
    }
    cellw.backgroundColor = [UIColor orangeColor];
    return cellw;

} else {

    CellForMyAimsTableViewCell *cell = [table dequeueReusableCellWithIdentifier:cellID];

    if (!cell) {
        cell = [[CellForMyAimsTableViewCell alloc] initWithFrame:CGRectZero];;
    }

    return cell;
}

}

And I delete:

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

        SOGoal *goal = self.tableData [indexPath.row];

            [[SOCoreDataManager sharedManager] deleteAim:goal];

            self.tableData = [NSMutableArray arrayWithArray:[[SOCoreDataManager sharedManager] getAllAims]];

            [self.tableView beginUpdates];
            [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
            [self.tableView endUpdates];

    }

}

Error:

2015-01-14 15:17:25.019 [5332:190142] *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-3318.16.14/UITableView.m:1582
2015-01-14 15:17:25.022 [5332:190142] *** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'Invalid update: invalid number of rows in section 0.  The number of rows contained in an existing section after the update (1) must be equal to the number of rows contained in that section before the update (1), plus or minus the number of rows inserted or deleted from that section (0 inserted, 1 deleted) and plus or minus the number of rows moved into or out of that section (0 moved in, 0 moved out).'
*** First throw call stack:
(
    0   CoreFoundation                      0x00000001050bcf35 __exceptionPreprocess + 165
    1   libobjc.A.dylib                     0x0000000104d55bb7 objc_exception_throw + 45
    2   CoreFoundation                      0x00000001050bcd9a +[NSException raise:format:arguments:] + 106
    3   Foundation                          0x00000001049725df -[NSAssertionHandler handleFailureInMethod:object:file:lineNumber:description:] + 195
    4   UIKit                               0x000000010337bc2a -[UITableView _endCellAnimationsWithContext:] + 11746
    5   nameapp                                0x00000001029777cf __69-[ListViewController tableView:commitEditingStyle:forRowAtIndexPath:]_block_invoke + 607
    6   nameapp                                0x000000010297ea10 __86+[SONetworkingWithLegendaryServer deleteAim:legendaryToken:aimId:onSuccess:onFailure:]_block_invoke + 112
    7   nameapp                                0x000000010296dad8 __64-[AFHTTPRequestOperation setCompletionBlockWithSuccess:failure:]_block_invoke46 + 40
    8   libdispatch.dylib                   0x0000000106673ba6 _dispatch_call_block_and_release + 12
    9   libdispatch.dylib                   0x00000001066917f4 _dispatch_client_callout + 8
    10  libdispatch.dylib                   0x000000010667a8fb _dispatch_main_queue_callback_4CF + 949
    11  CoreFoundation                      0x0000000105024fe9 __CFRUNLOOP_IS_SERVICING_THE_MAIN_DISPATCH_QUEUE__ + 9
    12  CoreFoundation                      0x0000000104fe7eeb __CFRunLoopRun + 2043
    13  CoreFoundation                      0x0000000104fe7486 CFRunLoopRunSpecific + 470
    14  GraphicsServices                    0x00000001070569f0 GSEventRunModal + 161
    15  UIKit                               0x00000001032a7420 UIApplicationMain + 1282
    16  nameapp                                0x00000001029c52e3 main + 115
    17  libdyld.dylib                       0x00000001066c6145 start + 1
)
libc++abi.dylib: terminating with uncaught exception of type NSException

Solution

  • You're getting the NSInternalInconsistencyException because your table will always have at least one row but when you swipe-to-delete the last row you're telling it you expect to end up with 0 cells. This obvious mismatch generates the exception.

    To fix it, tableView:commitEditingStyle:forRowAtIndexPath: needs to check for the "The user deleted the last row" case and handle it differently. When you're at the last row, you have two options:

    1. Refresh your existing index path (it should transform into the placeholder cell):

      [self.tableView beginUpdates];
      [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
      [self.tableView endUpdates];
      
    2. Delete the user's cell and insert the placeholder cell:

      [self.tableView beginUpdates];
      [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationLeft];
      [self.tableView insertRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:0 inSection:0]] withRowAnimation:UITableViewRowAnimationLeft];
      [self.tableView endUpdates];