← Назад к вопросам

Что такое CADisplayLink?

1.0 Junior🔥 32 комментариев
#Анимации и графика

Комментарии (2)

🐱
deepseek-v3.2PrepBro AI6 апр. 2026 г.(ред.)

Ответ сгенерирован нейросетью и может содержать ошибки

Что такое CADisplayLink?

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

Как работает CADisplayLink

В отличие от стандартных таймеров, таких как Timer (ранее NSTimer), который срабатывает на основе временных интервалов (например, каждые 0.016 секунд для 60 FPS), CADisplayLink напрямую связан с Vsync (вертикальная синхронизация) дисплея. Он вызывает заданный метод (селектор) каждый раз, когда система готовится к отрисовке нового кадра. Это обеспечивает:

  • Высокую точность: Вызовы происходят в момент, оптимальный для обновления интерфейса.
  • Энергоэффективность: Код выполняется только тогда, когда это действительно нужно для отрисовки, снижая нагрузку на CPU/GPU.
  • Избегание "разрывов" кадров: Синхронизация с дисплеем минимизирует артефакты в анимации.

Ключевые свойства и методы

CADisplayLink предоставляет несколько важных свойств для контроля:

  • timestamp: Время последнего отрисованного кадра (в секундах).
  • duration: Продолжительность между кадрами (например, ~0.016667 с для 60 Гц).
  • preferredFramesPerSecond: Позволяет задать желаемую частоту кадров (например, 30, 60, 120 FPS), хотя реальная частота зависит от возможностей дисплея.
  • isPaused: Флаг для приостановки/возобновления вызовов.
  • add(to:forMode:) и invalidate(): Методы для запуска и остановки связи с дисплеем.

Пример использования

Вот простой пример создания CADisplayLink для анимации перемещения объекта на экране (например, в игровом цикле):

import UIKit

class AnimationViewController: UIViewController {
    private var displayLink: CADisplayLink?
    private var startTime: CFTimeInterval = 0
    private let animationDuration: CFTimeInterval = 2.0 // Длительность анимации в секундах
    @IBOutlet weak var movingView: UIView!

    override func viewDidLoad() {
        super.viewDidLoad()
        setupDisplayLink()
    }

    private func setupDisplayLink() {
        // Создаем CADisplayLink с целевым методом
        displayLink = CADisplayLink(target: self, selector: #selector(updateAnimation))
        // Устанавливаем желаемую частоту кадров (например, 60 FPS)
        displayLink?.preferredFramesPerSecond = 60
        // Добавляем в основной RunLoop в режиме .common
        displayLink?.add(to: .main, forMode: .common)
        startTime = CACurrentMediaTime()
    }

    @objc private func updateAnimation() {
        let elapsed = CACurrentMediaTime() - startTime
        if elapsed >= animationDuration {
            // Завершаем анимацию
            displayLink?.invalidate()
            displayLink = nil
            return
        }

        // Вычисляем прогресс анимации (от 0 до 1)
        let progress = elapsed / animationDuration
        // Обновляем позицию view (например, перемещаем по горизонтали)
        let screenWidth = view.bounds.width
        movingView.frame.origin.x = CGFloat(progress) * screenWidth
    }

    override func viewWillDisappear(_ animated: Bool) {
        super.viewWillDisappear(animated)
        // Важно: останавливаем CADisplayLink при уходе с экрана
        displayLink?.invalidate()
    }
}

Сравнение с другими подходами

  • CADisplayLink vs Timer: Timer менее точен для анимации, так как зависит от RunLoop и может "дрейфовать" при высокой нагрузке системы. CADisplayLink гарантирует вызовы в момент отрисовки кадра.
  • CADisplayLink vs Core Animation: Для стандартных UI-анимаций (например, перемещение, масштабирование) лучше использовать встроенные анимации Core Animation (например, UIView.animate), так как они аппаратно ускорены. CADisplayLink полезен для кастомной логики, где нужно контролировать каждый кадр.
  • CADisplayLink vs Metal/SceneKit: В современных графических фреймворках (Metal, SceneKit) часто используется собственный цикл рендеринга, но CADisplayLink может служить для синхронизации неграфических задач (например, обновления физики в игре).

Плюсы и минусы

Плюсы:

  • Высокая точность синхронизации с дисплеем.
  • Эффективность для ресурсоемких задач (например, игры).
  • Гибкость в управлении частотой кадров.

Минусы:

  • Более сложный в использовании, чем стандартные анимации.
  • Требует ручного управления жизненным циклом (запуск/остановка).
  • Может создавать нагрузку на батарею, если используется без оптимизации.

Практические советы

  1. Всегда останавливайте CADisplayLink при уходе с экрана (в viewWillDisappear или deinit), чтобы избежать утечек памяти.
  2. Используйте режим .common в RunLoop для плавной работы во время пользовательского взаимодействия (например, скроллинга).
  3. Оптимизируйте код в методе обновления: избегайте тяжелых операций, чтобы не пропускать кадры.
  4. Учитывайте частоту дисплея: на устройствах с ProMotion (до 120 Гц) можно установить preferredFramesPerSecond для баланса между плавностью и производительностью.

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

Что такое CADisplayLink? | PrepBro