Я не смотрел разборку, чтобы увидеть, но мы используем немного другое решение. Установка свойства CATiledLayer.content
в nil
блоков и принудительное завершение всех блоков рендеринга в очереди. Это можно безопасно запустить в фоновом потоке, а затем выпустить UIView
можно вернуться в основной поток, чтобы позволить виду и слою освободиться.
Вот один из примеров реализации UIViewController dealloc
, который будет поддерживать ваше CATiledLayer
представление живым достаточно долго, чтобы безопасно остановить рендеринг, не блокируя основной поток.
- (void)dealloc
{
// This works around a bug where the CATiledLayer background drawing
// delegate may still have dispatched blocks awaiting rendering after
// the view hierarchy is dead, causing a message to a zombie object.
// We'll hold on to tiledView, flush the dispatch queue,
// then let go of fastViewer.
MyTiledView *tiledView = self.tiledView;
if(tiledView) {
dispatch_background(^{
// This blocks while CATiledLayer flushes out its queued render blocks.
tiledView.layer.contents = nil;
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.01 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
// Make sure tiledView survives until now.
tiledView.layer.delegate = nil;
});
});
}
}
Это предположение, но некоторые фреймворки/классы Apple (StoreKit, CATiledLayer, UIGestureRecognizer) утверждают, что имеют @property (weak) id delegate
реализации, но явно неправильно обрабатывают делегат weak
. Глядя на некоторые разборки, они делают явно связанные с гонкой проверки if != nil
, а затем напрямую касаются слабого свойства. Правильный способ — объявить __strong Type *delegate = self.delegate
, что либо завершится успешно и даст надежную ссылку, гарантированно сохранившуюся, либо будет nil
, но конечно не даст вам ссылку на объект-зомби (мой предполагаю, что код фреймворка не был обновлен до ARC).
Под капотом CATiledLayer
создает очередь отправки для выполнения фонового рендеринга и, по-видимому, либо касается свойства делегата небезопасным способом, либо получает локальную ссылку, но не делая ее строгой. В любом случае, отправленные блоки рендеринга с радостью отправят сообщение объекту-зомби, если делегат будет освобожден. Просто очистить делегат недостаточно — это уменьшит количество сбоев, но не устранит их безопасно.
Установка content = nil
вызывает dispatch_wait и блокирует до тех пор, пока все существующие блоки рендеринга в очереди не будут завершены. Мы возвращаемся к основному потоку, чтобы убедиться, что dealloc
в безопасности.
Если у кого-то есть предложения по улучшению, пожалуйста, дайте мне знать.
person
russbishop
schedule
01.12.2014