Можно ли работать с CALayer не из главного потока?

«Можно ли работать с CALayer не из главного потока?» — вопрос из категории UIKit, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нет, все операции с CALayer, влияющие на отображение, должны выполняться на главном потоке (Main Thread).

Правило: Core Animation не является thread-safe. Изменения иерархии слоев, анимации или свойств, влияющих на отображение, требуют главного потока.

Неправильно (вызовет краш или неопределенное поведение):

DispatchQueue.global().async {
    // ОПАСНО: изменение иерархии слоев не из главного потока
    let newLayer = CALayer()
    newLayer.backgroundColor = UIColor.red.cgColor
    view.layer.addSublayer(newLayer) // ✗ Может вызвать краш
}

Правильно (все UI-операции на главном потоке):

// 1. Подготовка данных в фоне
DispatchQueue.global(qos: .userInitiated).async {
    let image = self.processHeavyImage()
    let path = self.createComplexBezierPath()

    // 2. Применение изменений на главном потоке
    DispatchQueue.main.async {
        let imageLayer = CALayer()
        imageLayer.contents = image.cgImage
        imageLayer.frame = self.imageView.bounds

        let shapeLayer = CAShapeLayer()
        shapeLayer.path = path.cgPath
        shapeLayer.fillColor = UIColor.blue.cgColor

        // Безопасное добавление на главном потоке
        self.view.layer.addSublayer(imageLayer)
        self.view.layer.addSublayer(shapeLayer)
    }
}

Исключения (что можно делать в фоне):

  • Создание CGImage, CIImage, CGPath
  • Вычисления для анимаций (значения from, to, duration)
  • Подготовка данных для contents слоя

Проверка потока:

// Всегда проверяйте, если не уверены
if Thread.isMainThread {
    layer.opacity = 0.5
} else {
    DispatchQueue.main.async {
        layer.opacity = 0.5
    }
}

Диагностика: Включите CADebugger (CA_DEBUG_TRANSACTIONS=1) для обнаружения нарушений потокобезопасности.