NSInvalidArgumentException при удалении ячейки с использованием другого класса

StackOverflow https://stackoverflow.com/questions/9452952

  •  13-11-2019
  •  | 
  •  

Вопрос

Обновление кода: Следуя ответу Мэтью, я попытался исправить свой код, чтобы он был более правильным.Теперь код удаляет ячейку, но также происходит сбой и выдает ошибку:

* Закрытие приложения из-за неперехваченного исключения «NSInvalidArgumentException», причина:'* -[__NSPlaceholderArray initWithObjects:count:]:попытайтесь вставить нулевой объект из объектов[0]'

Код ниже взят из действия под названием checkboxTapped который находится в моем CustomCell код.Как только действие запускается, оно выдает ошибку.Я понял, что мой indexPath равно NULL, и это, скорее всего, проблема.Но я не знаю, как это исправить.

[self.textLabel setTextColor:[UIColor grayColor]];
[self.detailTextLabel setTextColor:[UIColor grayColor]];

parent = [[ViewController alloc] init];

db = [[DataObject alloc] init];
NSIndexPath *indexPath = [[parent tableView] indexPathForSelectedRow];

[[parent array] removeObjectAtIndex:[indexPath row]];
[db deleteTaskAtIndex:[indexPath row]];

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

[db release];
[parent release];

Старый: Я просмотрел свой код и распечатал массив, который использовал, и, похоже, все в порядке, но эта ошибка все еще сохраняется.

* Закрытие приложения из-за неперехваченного исключения «NSRangeException», причина:'* -[__NSArrayM RemoveObjectAtIndex:]:индекс 1 за пределами [0 ..0]'

Я предполагал, что это как-то связано с моим indexPath но не так уж и важно, насколько сильно я его изменю.

-(void)checkboxTapped:(id)sender
{
    [sender setSelected:YES];

    [self.textLabel setTextColor:[UIColor grayColor]];
    [self.detailTextLabel setTextColor:[UIColor grayColor]];

    parent = [[ViewController alloc] init];
    UITableView *tableView = parent.tableView;
    NSMutableArray *array = [[NSMutableArray alloc] initWithArray:parent.array];
    [parent release];

    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:[array count] inSection:1];

    [array removeObjectAtIndex:[indexPath row]];
    [db deleteTaskAtIndex:[indexPath row]];    
    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];

    [array release];

    [tableView endUpdates];
    [tableView reloadData];
}
Это было полезно?

Решение

В вашем коде [строка indexPath] будет возвращать значение [число массива].Вряд ли это то, чего вы хотите.Если в вашем массиве нет объектов, вы попытаетесь удалить объект с индексом 0.Но объектов не будет и вы получите ошибку.Если в вашем массиве есть 1 объект, вы попытаетесь удалить объект с индексом 1.Опять же, это не удастся, потому что нет объекта с индексом 1, а есть только один объект с индексом 0.

Если вы хотите удалить последний объект в массиве, вам нужно использовать индекс count-1.Вам также может потребоваться проверить, пуст ли массив, если такой случай возможен.

Обновлено в ответ на продолжение в комментарии

Ты не хочешь ничего делать indexPathWithIndex.Как первый шаг, попробуйте изменить свой код следующим образом:

-(void)checkboxTapped:(id)sender
{
    [sender setSelected:YES];

    [self.textLabel setTextColor:[UIColor grayColor]];
    [self.detailTextLabel setTextColor:[UIColor grayColor]];

    parent = [[ViewController alloc] init];  // looks very odd - is an instance of this viewController active when the checkBox is tapped? If so, you don't want to create a new one, you want to access the existing one
    UITableView *tableView = parent.tableView;
    [parent release];  // this looks very dicey - when you release the parent, won't it release the tableView too?!

    int lastRow = [array count] - 1;
    if (lastRow == 0)
    {
         return; // bail if there are no rows in the table
    }

    NSMutableArray *array = [[NSMutableArray alloc] initWithArray:parent.array];
    [array removeObjectAtIndex: lastRow];  // not clear this will do anything as the reference to array is discarded later

    [db deleteTaskAtIndex: lastRow];   

    NSIndexPath *indexPath = [NSIndexPath indexPathForRow: lastRow inSection:1]; 
    [tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationTop];

    [array release];

// [tableView endUpdates];  // there's no matching beginUpdates and you're only do one change operation anyway - leave this out

// [tableView reloadData]; // if you leave this line in, you won't see the delete animation - if you just want to delete one row, you wouldn't normally use reloadData, at least not if you want the animation
}

Учитывая все вышесказанное, похоже, что здесь происходят и другие вещи.

Что происходит с array?Вы создаете это, удаляете из него элемент и отбрасываете указатель на него.Это то, что вы действительно хотите сделать?Более распространенным шаблоном было бы получение указателя на массив из другого объекта и удаление элемента в его конце.

Из вашего кода неясно, как вы обновляете источник данных таблицы.Когда используешь deleteRowsAtIndexPaths:withRownAnimation вам необходимо убедиться, что источник данных таблицы вернет на одну строку меньше, чем в прошлый раз, когда его запрашивали с помощью tableView:numberOfRowsInSection:.Из вашего кода неясно, как источник данных tableView узнает, что на один элемент меньше, если, возможно, он не смотрит на то, что это такое. db указывает, чтобы это выяснить.

Более фундаментально, при типичном шаблоне проектирования tableView будет освобожден, когда вы освободите родительское представление, поэтому все, на что он указывает после `[parent Release]', будет делать что-то неопределенное и, вероятно, приведет к сбою, по крайней мере, некоторых из время.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top