Я не смотрел на разборку, чтобы увидеть, но мы используем немного другое решение. Установка для свойства 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
безопасен.
Если у кого-то есть предложения по улучшению, пожалуйста, дайте мне знать.