NSInvalidArgumentException при удалении ячейки с использованием другого класса - PullRequest
0 голосов
/ 26 февраля 2012

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

* Завершение работы приложения из-за необработанного исключения «NSInvalidArgumentException», причина: «* - [__ NSPlaceholderArray initWithObjects:count:]: попытка вставить объект nil из объектов [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];
}

1 Ответ

1 голос
/ 26 февраля 2012

В вашем коде [indexPath row] собирается вернуть значение [array count].Это вряд ли будет то, что вы хотите.Если в вашем массиве ноль объектов, вы попытаетесь удалить объект с индексом 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] 'будет делать что-то неопределенное и может произойти сбой, по крайней мере, иногда.

...