#iphone #uitableview #nszombie
#iPhone #uitableview #nszombie
Вопрос:
Я создал подкласс UITableViewCell с пользовательским указателем и использую его в двух разных UITableViews в моем приложении. Он отлично работает в одной из таблиц, но другая таблица выходит из строя, когда я ее интенсивно прокручиваю. Инструменты идентифицируют зомби в этом коде (в cellForRowAtIndexPath):
NSString *identifier = @"edit";
LogTableCell *cell = (LogTableCell*)[tableView dequeueReusableCellWithIdentifier:identifier];
if (!cell) {
cell = (LogTableCell*) [[[NSBundle mainBundle] loadNibNamed:@"LogTableCell" owner:self options:nil] objectAtIndex:0];
[cell retain]; // prevents zombies!
}
NSLog(@"%@: retainCount: %d", identifier, [cell retainCount]);
// some other cell init stuff
return cell;
Обратите внимание на строку [сохранить ячейку]; — когда она есть, код работает безупречно. Извлеките его и завершите работу. NSLog всегда сообщает о количестве удерживаемых файлов, равном 2, поэтому в этом не должно быть необходимости. Но если я сделаю что-то вроде этого:
if ([cell retainCount] < 1) { [cell retain]; } // does not prevent zombies!
это не работает. Нет alloc / init, поэтому мне не нужно выполнять автоматическое освобождение или вообще беспокоиться об этом, и я всегда думал, что cellForRowAtIndexPath освобождает ячейку для меня.
Когда я не использую инструменты, вот ошибка, которую я получаю от xcode:
*** -[CALayer retain]: message sent to deallocated instance 0x4d8e930
Даже если это работает со строкой [cell retain]; , для анализа (и для меня) это выглядит как утечка, поэтому я хотел бы решить проблему. Кто-нибудь знает, что здесь происходит?
Комментарии:
1. Я понял это с помощью небольшого отслеживания. Проблема заключалась в освобождении UITableViewCell с подклассом UITableViewCell. У меня было несколько переменных экземпляра и несколько свойств, все из которых я освобождал в dealloc. Но некоторые свойства были @synthesized для некоторых из этих переменных экземпляра, и когда они объединены таким образом, их коллективно нужно освободить только один раз. Итак, я прокомментировал выпуски переменных экземпляра, которые были привязаны к свойствам, и это устранило проблему. Я надеюсь, что это кому-нибудь поможет!
2. Рекомендуется избегать использования свойств в вашем методе dealloc. Вызов свойства может иметь нежелательные побочные эффекты. Освобождение вашего ivar позволяет избежать любых потенциальных проблем.
3. Это не огромная проблема, многие люди выпускают переменные через свойства, и Apple даже делает это в некоторых своих примерах кода… но при прочих равных условиях, получите прямой доступ к iVar.
4. Спасибо за комментарий! Когда вы говорите «использование свойств в вашем методе освобождения», вы имеете в виду «освобождение свойств в вашем методе освобождения?»
5. Я имею в виду сказать:
self.property = nil;
вместо[property release];
Ответ №1:
Не вызывайте retainCount
Абсолютное количество сохранений бесполезно.
([cell retainCount] < 1)
не может работать; retainCount
никогда не может вернуть ноль.
(Да — загрузка кончика в cellForRowAtIndexPath:
теперь благословлена фреймворком. Coolio.)
Тогда ваша проблема заключается в другом, поскольку этот код (без сохранения) верен.
По-прежнему весьма вероятно, что это утечка пула автоматического выпуска, которая происходит перед утечкой обычного цикла событий. В частности, что-то где-то имеет слабую ссылку на ячейку, которой не должно быть.
Если вы запустите инструмент распределения и включите запись событий сохранения / освобождения, вы можете точно увидеть, где происходят вызовы для сохранения / освобождения / автоматического освобождения объекта. Событие, вызывающее сбой, имеет очевидную ценность.
В этом случае, однако, вам, вероятно, где-то не хватает пары сохранить / освободить. По крайней мере, это было бы исправлением симптомов. Реальная проблема, вероятно, заключается в каком-то переходе пользовательского интерфейса, который происходит таким образом, что часть содержимого фактически преждевременно извлекается, в то время как какой-то другой раздел вашего приложения все еще зависит от него. Добавление пары сохранения / освобождения таким образом, чтобы продолжительность жизни ячейки сохранялась при этом переходе, на самом деле не является исправлением, поскольку могут быть другие зависимости.
Комментарии:
1. Не должно быть никаких проблем с производительностью при выполнении пользовательского
UITableViewCell
таким образом. Я сделал что-то почти идентичное без снижения производительности, и это очень близко к рекомендации Apple .2. Я делал это раньше, и я не видел никаких проблем с производительностью, что бы там ни было. Кроме того, я предположил, что retainCount никогда не сможет вернуть ноль, но я решил, что попробовать стоит.