Что такое CADisplayLink? Для чего его используют?ios-92

Что такое CADisplayLink?

CADisplayLink — это специальный таймер в iOS/macOS, который синхронизируется с частотой обновления экрана устройства (обычно 60 или 120 Гц). Это механизм уровня Core Animation, позволяющий привязывать выполнение кода к VSync-сигналу дисплея.

Ключевые характеристики:

  • Прямая интеграция с системой отображения
  • Вызов с частотой обновления экрана (frame rate)
  • Высокая точность временных интервалов
  • Низкая задержка (low-latency)

Основные сценарии использования

1. Плавная анимация

Идеально для кастомных анимаций, где требуется полный контроль:

let displayLink = CADisplayLink(target: self, selector: #selector(updateAnimation))
displayLink.add(to: .main, forMode: .common)

@objc func updateAnimation() {
    // Обновление параметров анимации
    progress += 0.01
    layer.position = CGPoint(x: progress * 100, y: 50)

    if progress >= 1.0 {
        displayLink.invalidate()
    }
}

2. Игровой цикл

Для кастомных игровых движков или физических симуляций:

var lastTimestamp: CFTimeInterval = 0

@objc func gameUpdate(displayLink: CADisplayLink) {
    let deltaTime = displayLink.timestamp - lastTimestamp
    lastTimestamp = displayLink.timestamp

    updateGameState(deltaTime: deltaTime)
    renderGame()
}

3. Профилирование производительности

Измерение FPS и анализ производительности:

var frameCount = 0
var lastFPSUpdate: CFTimeInterval = 0

@objc func monitorFPS(displayLink: CADisplayLink) {
    frameCount += 1
    let currentTime = displayLink.timestamp

    if currentTime - lastFPSUpdate >= 1.0 {
        print("Current FPS: \(frameCount)")
        frameCount = 0
        lastFPSUpdate = currentTime
    }
}

Конфигурация CADisplayLink

Основные свойства:

// Частота обновления (read-only)
let preferredFramesPerSecond: Int

// Приостановка
var isPaused: Bool

// Текущее время кадра
var timestamp: CFTimeInterval

// Длительность предыдущего кадра
var duration: CFTimeInterval

Настройка частоты:

if #available(iOS 15.0, *) {
    displayLink.preferredFrameRateRange = CAFrameRateRange(minimum: 30,
                                                         maximum: 120,
                                                         preferred: 60)
}

Преимущества перед другими таймерами

  1. Высокая точность — привязка к аппаратному VSync
  2. Энергоэффективность — синхронизирован с дисплеем
  3. Автоподстройка — адаптируется к ProMotion дисплеям (120 Гц)
  4. Минимальный дрейф — нет накопления ошибки как у NSTimer

Важные нюансы использования

  1. Всегда добавляйте на основной RunLoop:

    displayLink.add(to: .main, forMode: .common)
    
  2. Обязательно инвалидируйте при завершении:

    displayLink.invalidate()
    
  3. Для плавности используйте timestamp и duration:

    let frameProgress = (displayLink.timestamp - startTime) / totalDuration
    
  4. Избегайте тяжелых вычислений в колбэке

Современные альтернативы

Для SwiftUI можно использовать TimelineView с частотой обновления:

TimelineView(.animation) { context in
    // Автоматическая синхронизация с частотой обновления
}

Резюмируем:

CADisplayLink — это мощный инструмент для синхронизации кода с частотой обновления экрана, идеально подходящий для плавных анимаций, игровых циклов и задач, требующих точного временного контроля. Его ключевое преимущество — прямая интеграция с системой визуализации iOS.