9

I'm currently working on an implementation of an inline UIDate picker inside of a UITableViewCell.

I'm able to show and hide this picker cell when I select the cell directly above where that cell should be inserted, which is the behavior that I expect. However, the app crashes if I select any other cells in the table view:

*** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-3318.16.14/UITableView.m:1582

After looking at the accepted answer to this SO question, I added an exception breakpoint, and I've found out that the app is crashing at the call to [tableView endUpdates]; in didSelectRowAtIndexPath:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];

    // Check to see if the "Only Alert From" row was selected. The cell with the picker should be below this one.
    if (indexPath.section == TimeOfDaySection && indexPath.row == HourTimeZoneRow  && self.timePickerIsShowing == NO){

        [tableView beginUpdates];
        [self showTimePicker];
        [tableView endUpdates];

    } else{
        [tableView beginUpdates];
        [self hideTimePicker];
        [tableView endUpdates];
        [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
    }
    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}

That said, I'm not sure how to proceed. If I comment out the call to [tableView endUpdates];, the app won't crash when other cells are selected, BUT the cell with the picker view won't hide. Does anyone have any suggestions? Thank you!

EDIT: Below is my code for showTimePicker and hideTimePicker:

- (void)showTimePicker
{
    self.timePickerIsShowing = YES;
    self.timePicker.hidden = NO;

    //Create the index path where we insert the cell with the picker
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:HourTimeZoneRow + 1 inSection:TimeOfDaySection];

    [self.tableView beginUpdates];
    [self.tableView insertRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    [self.tableView endUpdates];

    self.timePicker.alpha = 0.0f;
    [UIView animateWithDuration:0.25 animations:^{
        self.timePicker.alpha = 1.0f;
        //This is the row where the picker cell should be inserted
        [self.tableView reloadRowsAtIndexPaths:@[[NSIndexPath indexPathForRow:HourTimeZoneRow + 1 inSection:TimeOfDaySection]] withRowAnimation:UITableViewRowAnimationFade];
        [self.tableView reloadData];
    }];
}

- (void)hideTimePicker {
    self.timePickerIsShowing = NO;
    self.timePicker.hidden = YES;

    //Create the index path where we delete the cell with the picker
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:HourTimeZoneRow + 1 inSection:TimeOfDaySection];
    [self.tableView beginUpdates];
    //Delete the picker row
    [self.tableView deleteRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationFade];
    [self.tableView endUpdates];
    [UIView animateWithDuration:0.25
                     animations:^{
                         self.timePicker.alpha = 0.0f;
                     }
                     completion:^(BOOL finished){
                         self.timePicker.hidden = YES;
                     }];
}

EDIT 2: After reading this SO thread, I believe the problem may be with my numberOfRowsInSection method:

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    switch (section) {
        case NotificationsSection:
            return TotalPreferencesRows;
            break;
        case RedZoneSection:
            return TotalRedZoneRows;
            break;
        case TimeOfDaySection:
            if (self.timePickerIsShowing) {
                return TotalTimeOfDayRows + 1;
            }
//            else if (self.timePickerIsShowing == NO){
//                return TotalTimeOfDayRows;
//            }
            else{
                return TotalTimeOfDayRows;
            }
            return TotalTimeOfDayRows;
            break;
        default:
            return 0;
            break;
    }
}
Community
  • 1
  • 1
narner
  • 2,908
  • 3
  • 26
  • 63
  • Could you post the code for your show/hide TimePicker methods? It would be helpful to see how are you displaying the timePicker – Alex Feb 16 '15 at 15:59
  • Yes of course, my apologies! – narner Feb 16 '15 at 15:59
  • Please show the crash log. Also, add an exception breakpoint to show where it crashes. – Fogmeister Feb 16 '15 at 16:18
  • Hi @Fogmeister, thank you, I will post the crash log. I did add an exception breakpoint; I will edit my question to make that more clear. – narner Feb 16 '15 at 16:20

2 Answers2

4

Not sure if this is the source of the crash, but it's not recommended to call beginUpdates multiple times which you're doing in
[tableView beginUpdates]; [self showTimePicker]; [tableView endUpdates]; because showTimePicker calls [self.tableView beginUpdates];

Micky
  • 5,578
  • 7
  • 31
  • 55
  • Thank you Kim, I just took out the calls for being and end updates in 'didSelectRowAtIndexPath', but this time the crash occurred on the call to '[tableView endUpdates];' in 'hideTimePicker' – narner Feb 16 '15 at 16:18
  • Just to be sure: Did you take out ALL calls to begin/endUpdates in didSelectRowAtIndexPath? Also the ones around `[self hideTimePicker];`? – Micky Feb 16 '15 at 16:49
  • Yes, I took out all calls to begin/endUpdates in didSelectRowAtIndexPath. The only places those calls exist are in my show/hideTimePicker methods. – narner Feb 16 '15 at 16:56
  • Could you post the exception that is thrown? – Micky Feb 16 '15 at 17:06
  • It seems to be this: *** Assertion failure in -[UITableView _endCellAnimationsWithContext:], /SourceCache/UIKit_Sim/UIKit-3318.16.14/UITableView.m:1582 – narner Feb 16 '15 at 17:14
2

The problem is in your didSelectRowAtIndexPath, you call the hide method even though it might not be showing. Make the else clause into an else if, like this:

- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];

    // Check to see if the "Only Alert From" row was selected. The cell with the picker should be below this one.
    if (indexPath.section == TimeOfDaySection && indexPath.row == HourTimeZoneRow  && self.timePickerIsShowing == NO){

        [tableView beginUpdates];
        [self showTimePicker];
        [tableView endUpdates];

    } else if (indexPath.section == TimeOfDaySection && indexPath.row == HourTimeZoneRow  && self.timePickerIsShowing == YES){
        [tableView beginUpdates];
        [self hideTimePicker];
        [tableView endUpdates];
        [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
    }
    [self.tableView deselectRowAtIndexPath:indexPath animated:YES];
}
pbasdf
  • 21,386
  • 4
  • 43
  • 75