Пока лучший ответ, который у меня есть, как я подозреваю:
Начиная с OS X 10.7 и iOS 5, NSIndexPath
является поточно-ориентированным. До этого экземпляры были поточно-ориентированными, потому что они неизменны, но общий доступ к существующим экземплярам не является.
Для моего метода, который возвращает пути к индексам по требованию, я сделал это:
- (NSIndexPath *)indexPath;
{
NSIndexPath *result = … // create the path as appropriate
return [[result retain] autorelease];
}
С момента реализации этой последней строки кода у нас больше не было отчетов о сбоях из путей индекса.
Пути индекса создаются -indexPathByAddingIndex:
или +indexPathWithIndex:
.
Результаты, которые я вижу, убедили меня, что (до 10.7 / iOS5) эти методы возвращали существующий экземпляр NSIndexPath
. Этот экземпляр никак не сохраняется текущим потоком, поэтому поток, который первым создал экземпляр (в нашем случае, main), освобождает путь (вероятно, путем извлечения пула автоматического выпуска) и оставляет наш рабочий поток с висящим указателем, который вылетает при использовании, как видно из вопроса.
Это все немного страшно, потому что, если мой анализ верен, добавленный мною танец retain
/ autorelease
просто заменяет одно состояние гонки другим, менее вероятным.
До 10.7 / iOS5 я мог думать только об одном верном обходном пути: ограничить все пути создания индексов основным потоком. Это может быть довольно медленным, если такой код часто вызывается, поэтому его можно улучшить - за счет памяти - за счет поддержки своего собственного кеша экземпляров для использования фоновыми потоками. Если кэш сохраняет путь, то вы знаете, что он не будет освобожден основным потоком.