Пользовательский UITableViewCell, нарисованный с помощью CoreGraphics и проблем с потоками

Я использую базовую графику для рисования настраиваемого UITableViewCell на основе образца Fast TableView от Лорена Брихтера.

Я использую некоторые iVars в пользовательском классе ячеек, который я создаю как атомарный (многопоточный) с сильной ссылкой (следовательно, ARC).

Теперь проблемы начинаются, когда я начинаю слишком быстро прокручивать tableView. Я получаю случайные сбои в методе - (void)drawContentView:(CGRect)rect, который я подклассифицирую для выполнения пользовательского рисунка.

Проблема в том, что iVars, которые я использую в пользовательском классе ячеек, были освобождены, а память теперь принадлежит другим объектам, что, конечно же, приводит к сбоям.

Я попытался использовать директиву @synchronized для всего кода отрисовки, чтобы принудительно заблокировать мьютекс кода отрисовки, но это не решило проблему.

Кто-нибудь еще сталкивался с этой проблемой и знает решение проблемы?


person Lefteris    schedule 07.06.2012    source источник


Ответы (1)


Atomic не всегда означает «многопоточность». Это просто означает, что когда вы используете геттер, вы получите на нем дополнительную пару сохранения / автоматического выпуска (чтобы он не мог исчезнуть во время цикла выполнения), и он будет @synchronized с сеттером, чтобы вы могли Не получается получить половину объекта, если установка и получение сталкиваются. Все это верно только в том случае, если вы используете геттеры и сеттеры. У вас не должно быть прямого доступа к ivars. Если да, то атомарность ничего не значит.

Вы также можете изменять основной контекст UIKit в потоке, отличном от основного потока. Вы не можете этого сделать. Основной контекст UIKit (тот, который использует drawRect:) действителен только в основном потоке.

person Rob Napier    schedule 07.06.2012
comment
Роб, я рисую с GCD. Я использую CALayer. Я рисую все в фоновом потоке, затем получаю контекст как изображение и устанавливаю содержимое слоя для этого изображения в основном потоке ... Это неправильно? Если да, то как мне это сделать правильно? И вы говорите, что я не должен сам получать доступ к иварам. Если нет, как передать текстовую строку из класса uitableview в пользовательскую ячейку, чтобы я мог ее нарисовать? - person Lefteris; 08.06.2012
comment
Пока последний setContents: выполняется в основном потоке, проблем определенно нет (обычно вы можете вызывать [CALayer setContents:] в любом потоке). Что касается доступа к ivar, я имею в виду, что вы не должны напрямую обращаться к ivar (foo), даже внутри объекта. Вы всегда должны использовать аксессуар (self.foo). Исключения составляют init, dealloc и сами средства доступа. - person Rob Napier; 08.06.2012
comment
Спасибо, Роб. Это была проблема с доступом к iVar. Я действительно не знал, что доступ к ним как к foo vs self.foo имеет такую ​​разницу. Мне также интересно, почему foo vs self.foo должны указывать на другое место в памяти, поскольку это один и тот же объект. Вы объясняете это в своей книге? - person Lefteris; 08.06.2012
comment
Да, глава 3. Проблема здесь в том, что когда вы вызываете self.foo и foo атомарно, вы получаете сохраняемую и автоматически выпускаемую версию foo. Поэтому, если кто-то вызывает setFoo: в другом потоке, ваша ссылка остается действительной для остальной части цикла выполнения. Но если вы используете foo напрямую, то, если кто-то вызовет setFoo :, теперь вы можете указывать на освобожденную память. - person Rob Napier; 08.06.2012
comment
Спасибо за объяснение, Роб. У меня есть книга, и я буду читать ее еще раз внимательнее, так как читаю только ее части. - person Lefteris; 08.06.2012