it-swarm.com.ru

Что означает сообщение "без индекса пути для повторного использования ячейки таблицы" в iOS 6/7?

С начала компиляции моего приложения с iOS 6 (а также с iOS 7) я начал видеть это сообщение. Я знаю, что UITableViews управляют ячейками по-другому в iOS 6, но мне не нужно было изменять мой код, чтобы он продолжал работать. Но я обеспокоен тем, что это сообщение может указывать на какую-то потенциальную проблему, которую я пока не вижу…. Кто-нибудь может пролить свет?

57
Nathan Brown

Эта ошибка появилась в журнале iOS 7 beta 5 и более поздних версий, в том числе в сборке iOS 7 GM/Release, хотя этого никогда не происходило в моем приложении в iOS 6 или более ранних бета-версиях iOS 7. После долгих экспериментов я нашел причину:

Я использовал объекты UITableViewCell для представлений заголовка раздела и возвращал их в tableView:viewForHeaderInSection:. Это кажется обычной практикой, особенно с iOS 5, когда стало легко проектировать представление заголовка раздела как ячейку представления таблицы-прототипа в StoryBoard с Interface Builder.

Когда я изменил свое приложение, чтобы использовать только обычные подклассы UIView для моих представлений заголовка раздела, ошибки исчезли, и, что более важно, мое представление таблицы прекратило случайное удаление заголовков раздела!

Может показаться, что (начиная с iOS 7 beta 5) UITableView внутренне поддерживает отображение всех объектов UITableViewCell в своей иерархии представления и их соответствующие пути индекса. Так как заголовок раздела (или заголовок табличного представления нижнего колонтитула) не имеет пути индекса, если вы используете объект UITableViewCell для этих представлений, табличное представление будет сбито с толку, когда оно найдет UITableViewCell, для которого у него нет путь индекса, приводящий к ошибке «нет пути индекса для повторного использования ячейки таблицы» и, если вам не повезло, отображает сбои в табличном представлении:

UPDATE: если у вас есть доступ к форумам Apple Dev, вот ветка об этом (которую я начал): https://devforums.Apple.com/message/882042#882042

Как предлагается в этом потоке, если вы не хотите многократно пересчитывать множители, вы можете создать оболочку UIView вокруг вашей UITableViewCell и вернуть ее в качестве представления заголовка раздела. 

UIView *view = [[UIView alloc] initWithFrame:[cell frame]];
[view addSubview:cell];

return view;

Однако обратите внимание, что этот подход «обертки» UIView не будет хорошо работать с AutoLayout и ротацией устройств, поэтому я предлагаю использовать подкласс UIView для ячеек верхнего и нижнего колонтитула, а не подкласс UITableViewCell, как описано в основной части ответа.

132
mluisbrown

Я бы возвратил contentView UITableViewCell вместо создания обертки ... имея в виду, что ограничение привязки зафиксировано в storybord

return cell.contentView;
41
mar-schmidt

У меня была та же проблема, и мне понадобилось несколько часов, чтобы разобраться с ней. Оказывается, я вызывал [textField becomeFirstResponder] при настройке ячеек (здесь textField был частью пользовательской ячейки tableview); [textField becomeFirstResponder]in превращает сообщения в сообщение keyboardWillShow, что, в свою очередь, приводило к преждевременной загрузке представления таблицы, что приводило к печально известному сообщению " нет пути индекса для повторного использования ячейки таблицы ". После удаления этого вызова проблема исчезла.

26
mpprdev

В дополнение к принятому ответу (mluisbrown) мне нужно было добавить маску autoresizingMask в ячейку заголовка, так как моя содержала многострочную метку, т.е.

UIView *view = [[UIView alloc] initWithFrame:[cell frame]];
cell.autoresizingMask = UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth;
[view addSubview:cell];
return view;
16
Rob

Это внутренняя ошибка UIKit - как упоминалось на собственных форумах разработчиков Apple. Якобы это исправлено в новых версиях xcode, хотя я не смог найти информацию о том, какая версия исправляет это.

8
diegoreymendez

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

Видимо, переопределенная -(void)setEditing:animated: моей пользовательской ячейки возвращалась слишком долго.

Мой предыдущий код был:

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{   
    [super setEditing:editing animated:animated];
    [self someAdditionalCode];
}

Я смог это исправить, изменив его на:

- (void)setEditing:(BOOL)editing animated:(BOOL)animated
{   
    [super setEditing:editing animated:animated];

    // DRM: we want to perform the actions from this block in the main thread, but
    // asynchronously to avoid excessive delays which were causing issues.
    //
    dispatch_async(dispatch_get_main_queue(), ^void()
    {
        [self someAdditionalCode];
    });
}
4
diegoreymendez

Выполнение моих endupdates после того, как resignfirstresponder решил мою проблему (есть UITextFIeld в моей пользовательской ячейке)

-(void)textfieldEditDone
{
....

    [textField resignFirstResponder];
    [self.tableView endUpdates];
2
Daniel Åkesson

У меня была такая же проблема с появлением сообщения об ошибке. Насколько я вижу, это вызвано перезагрузкой табличного представления из функции, вызываемой текстовым полем, как часть его протокола делегата. Т.е. textFieldDidEndEditing -> [controller.tableview reload ...]

2
Dan

Для записи, я также столкнулся с этим сообщением при работе под iOS 6. Похоже, что некоторый код, либо унаследованный, либо импортированный, имел что-то вроде этого

(NSInteger)tableView:(UITableView *)tv numberOfRowsInSection:(NSInteger)section {
    NSInteger rows = 0;
    if ([delegate respondsToSelector:@selector(numberOfItemsInSection:)]) {
        rows = [delegate numberOfItemsInSection:section];

        [tableView beginUpdates];
        [tableView endUpdates];
    }
}

Когда последовательность beginUpdate:/endUpdate: была удалена, проблема волшебным образом исчезла.

1
Fred The Bishop

Это, очевидно, старый вопрос, но, надеюсь, это может помочь любому, кто все еще сталкивается с этой проблемой в iOS8 +, потому что это все еще главный вопрос, который возникает для этого конкретного сообщения об ошибке.

Я использовал PINRemoteImage для асинхронной загрузки изображения в UIImageView, который был внутри пользовательского UITableViewCell.

Чтобы правильно изменить размер строки (динамическая высота ячеек с использованием автоматического макета) после загрузки изображения, я вызвал:

self.tableView beginUpdates;
self.tableView endUpdates;

Затем я получил сообщение «нет пути к индексу для повторного использования ячейки таблицы», и приложение зависало. Я думал, что блок PINRemoteImageManagerResult находится в главном потоке, однако оказывается, что это не так - поэтому устранение проблемы было вызвано тем, что начало/конец обновления были вызваны в главном потоке.

dispatch_async(dispatch_get_main_queue(), ^(void){
                            [self.tableView beginUpdates];
                            [self.tableView endUpdates];
});
1
siburb

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

NSIndexPath *reloadRow = [NSIndexPath indexPathForRow:1 inSection:2];
[self._mainTableView reloadRowsAtIndexPaths:@[reloadWebViewRow]
                           withRowAnimation:UITableViewRowAnimationFade];

Но случайно набрал

NSIndexPath *reloadRow = [NSIndexPath indexPathForItem:1 inSection:2];

Обратите внимание на разницу между двумя индексными путями: один создается с помощью indexPathForItem (неверно), а другой - с indexPathForRow (правильно). Все это привело к очень странному поведению tableView и сообщению об ошибке в заголовке. 

0
Tobias

Кажется, что моя проблема была вызвана, когда я пытался обновить пользовательский интерфейс в части кода, который был обратным вызовом от веб-вызова. Я решил, заставив обновления пользовательского интерфейса в основном потоке. Я использовал такой код.

void runOnMainQueueWithoutDeadlocking(void (^block)(void)){
    if ([NSThread isMainThread])
    {
        block();
    }
    else
    {
        dispatch_sync(dispatch_get_main_queue(), block);
    }
}

Я называю это следующим образом в блоке успеха моего фонового веб-вызова.

runOnMainQueueWithoutDeadlocking(^{
    [self.tableView beginUpdates];
    [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:1] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.tableView reloadSections:[NSIndexSet indexSetWithIndex:2] withRowAnimation:UITableViewRowAnimationAutomatic];
    [self.tableView endUpdates];
});
0
Brackston Mayhall

Еще одно условие ...

Это произошло, когда, не желая заголовка, я вернул nil.

Исправлено:

func tableView(tableView: UITableView,
               titleForHeaderInSection section: Int) -> String? {
    return ""
}
0
SwiftArchitect

Ну, я просто использовал большую часть дня, пытаясь выяснить это, так что, надеюсь, это альтернативное объяснение сэкономит кому-то еще некоторое время.

У меня был просмотр таблицы, которая давала это сообщение иногда , при загрузке. Это, как оказалось, было вызвано уведомлениями KVO о запуске объектов Core Data во время загрузки представления. (Наблюдая за изменением, мой контроллер попытался вызвать reloadData для рассматриваемой таблицы. Исправлено - не наблюдал объекты, пока представление не завершило загрузку (ранее я начал наблюдать объект, как только он был назначен через средство доступа)

TLDR: проверьте, не пытаетесь ли вы перезагрузить данные из чего-то другого, кроме основного потока.

0
Jonathan Zhan