UITableView deleteRowsAtIndexPath вылетает при удалении последней записи - PullRequest
13 голосов
/ 22 января 2012

При удалении последней записи из UITableView возникает следующая ошибка.

Завершение приложения из-за необработанного исключения «NSInternalInconsistencyException», причина: «Неверное обновление: недействительно количество строк в разделе 0. Количество строк, содержащихся в существующий раздел после обновления (3) должен быть равен количеству строки, содержащиеся в этом разделе до обновления (1), плюс или минус количество строк, вставленных или удаленных из этого раздела (1 вставлено, 1 удалено) и плюс или минус количество строк, перемещенных в или из этот раздел (0 переместился, 0 переместился). '

Моя цель - показать "Запись не найдена", если массив таблицы пуст.

Это код, который я использую. Когда я удаляю последнюю запись из массива таблицы, приложение вылетает. Как можно перезагрузить таблицу и показать ярлык «Запись не найдена»?

// Customize the number of rows in the table view.
- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section {
    if ([idArray count]==0) {
        return  3;
    }
    else 
    {
        return [idArray count];
    }   
}

// Customize the appearance of table view cells.
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {

    NSLog(@"array count %d",[idArray count]);
    if ([idArray count] == 0) {
        static NSString *CellIdentifier = @"Cell";

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier];
        }
        cell.textLabel.textAlignment = UITextAlignmentCenter;

        tableView.userInteractionEnabled = NO;

        self.navigationItem.leftBarButtonItem.enabled = NO;
         NSUInteger row = [indexPath row];

        switch (row) {
            case 0:
                cell.textLabel.text = @"";
                break;
            case 1:
                cell.textLabel.text = @"";
                break;

            case 2:
                cell.textLabel.text = @"No Records Found";
                break;


            default:
                break;
        }        

        return cell;
    }
    else
    {   static NSString *CellIdentifier = @"Cell";

        UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:CellIdentifier];
        if (cell == nil) {
            cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleSubtitle reuseIdentifier:CellIdentifier];
        }

        tableView.userInteractionEnabled = YES;

        self.navigationItem.leftBarButtonItem.enabled = YES;

        // Set up the cell
        identify *idItems = [idArray objectAtIndex:indexPath.row];

        NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
        [formatter setDateFormat:@"dd MMM,yyyy"];
        NSString *dateStr = [formatter stringFromDate:idItems.Date];
        UIImageView *accDis = [[UIImageView alloc] initWithImage:[UIImage imageNamed:@"Arrow.png"]];    
        cell.accessoryView = accDis;
        self.idTableView.separatorColor = [UIColor colorWithRed:150.0/255.0 green:150.0/255.0 blue:150.0/255.0 alpha:1];
        cell.textLabel.textColor = [UIColor blackColor];
        cell.textLabel.font = [UIFont boldSystemFontOfSize:18];
        cell.textLabel.adjustsFontSizeToFitWidth = YES;
        cell.detailTextLabel.textColor = [UIColor colorWithRed:100.0/255.0 green:100.0/255.0 blue:100.0/255.0 alpha:1];
        cell.detailTextLabel.font = [UIFont italicSystemFontOfSize:16];
        cell.detailTextLabel.adjustsFontSizeToFitWidth = YES;

        NSString *detailText = [NSString stringWithFormat:@"%@ - %@",dateStr,idItems.GeoCode];

        if (idItems.Image == NULL) {
            cell.imageView.image = [UIImage imageNamed:@"icon58x58.png"];
        }
        else
        {
        //pass image to fix size 50 X 50
        //UIImage *newImage = [self postProcessImage:idItems.Image];
            cell.imageView.image = idItems.thumb;//newImage; 
        cell.imageView.contentMode=UIViewContentModeScaleAspectFill;
        }

        cell.textLabel.text = idItems.TypeName; 
        cell.detailTextLabel.text = detailText;

        return cell;   
    }    
}

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

    if(editingStyle == UITableViewCellEditingStyleDelete) {

        if ([idArray count] >=1) 
        {
            [idTableView beginUpdates];

            //Get the object to delete from the array.
            identifyObject = [appDelegate.idArray objectAtIndex:indexPath.row];

            //Delete the object from the table.
            [self.idTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
             [appDelegate removeID:identifyObject];

            if ([idArray count] == 0) {
                [self.idTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
            }
            [idTableView endUpdates];
        }
    }
}

Ответы [ 3 ]

14 голосов
/ 22 января 2012

Проблема заключается в том, что табличное представление ожидает, что операции, выполняемые в представлении, соответствуют источнику данных. У вас есть одна запись в таблице, и вы удалите ее. В табличном представлении ожидается, что источник данных теперь будет содержать ноль записей, но из-за вашей логики «нет записей» он на самом деле возвращает значение 3, отсюда ошибка согласованности и ваш сбой.

Ошибка, кажется, эта часть:

if ([idArray count] == 0) {
    [self.idTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}

Я предполагаю, что это было предназначено для вставки строки "нет записей найдено" в таблицу при удалении последней строки, но, так как ваши "записи не найдены" на самом деле занимают три строки, вам нужно вместо этого вставить три строки, например это:

if ([idArray count] == 0) {
    [self.idTableView insertRowsAtIndexPaths:[NSArray arrayWithObjects:
    [NSIndexPath indexPathForRow:0 inSection:indexPath.section],
    [NSIndexPath indexPathForRow:1 inSection:indexPath.section],
    [NSIndexPath indexPathForRow:2 inSection:indexPath.section],
    nil] withRowAnimation:UITableViewRowAnimationFade];
}

Однако для вашего же здравомыслия я могу предложить другой подход? Вместо того, чтобы пытаться синхронизировать вашу таблицу и источник данных при манипулировании этими поддельными тремя строками данных, которые существуют только для целей отображения, почему бы просто не вставить UILabel в иерархию представлений (перед или за табличным представлением) с надписью " записи не найдены "и показать / скрыть это в зависимости от того, есть ли в таблице какие-либо данные? Таким образом, вы можете точно контролировать его положение и внешний вид, не прибегая к логике источника данных.

10 голосов
/ 22 января 2012

Общие правила удаления строк:

  1. Сделка с вашей моделью
  2. Сделка с анимацией строки

Так, например:

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

   if (editingStyle == UITableViewCellEditingStyleDelete) {
       NSInteger row = [indexPath row];

       [yourModel removeObjectAtIndex:row]; // you need to update your model

       [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath]    withRowAnimation:UITableViewRowAnimationFade];
    }
}

Теперь, по моему мнению, правильный код может быть следующим (я написал несколько комментариев, чтобы помочь вам).

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

    if (editingStyle == UITableViewCellEditingStyleDelete) {
        //Get the object to delete from the array.
        identifyObject = [appDelegate.idArray objectAtIndex:indexPath.row];
        [appDelegate removeID:identifyObject]; // update model first

        // now you can check model count and do what you want
        if ([appDelegate.idArray count] == 0) // I think you mean appDelegate.idArray
        {   
            // do what you want
            // with  [self.idTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        }

        else
        {
            [self.idTableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
        }
    }
}

Надеюсь, это поможет.

2 голосов
/ 04 сентября 2015

Я использовал тот же подход, где я использовал ячейку для предупреждения «Нет строк».

Для меня это сработало:

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

if (editingStyle == UITableViewCellEditingStyleDelete) {

    [favs removeObjectAtIndex:indexPath.section];

    if ([favs count] == 0) {
        [tableView reloadRowsAtIndexPaths:[[NSArray alloc]initWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationFade];
        [tableView setEditing:NO animated:YES];

        // Remove Edit bar button item
        self.navigationItem.rightBarButtonItem = nil;
    }
    else {
        // Animate the deletion from the table.
        [tableView deleteRowsAtIndexPaths:[[NSArray alloc]initWithObjects:indexPath, nil] withRowAnimation:UITableViewRowAnimationFade];
    }
}

}

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...