Почему ActivityIndicator в UIKit продолжает анимацию после остановки в дебаггере?

Ответ

ActivityIndicator продолжает анимацию после паузы в дебаггере, потому что анимация управляется системным уровнем (Core Animation) и не зависит от выполнения кода в главном потоке. Когда дебаггер приостанавливает выполнение, главный поток блокируется, но запланированные анимации в CALayer продолжают выполняться.

Техническая причина:

  • Анимация UIActivityIndicatorView реализована через CAAnimation в отдельном потоке рендеринга.
  • Команда stopAnimating() лишь устанавливает флаг и планирует обновление слоя, которое не может выполниться при заблокированном главном потоке.

Пример проблемы:

activityIndicator.startAnimating()
// Точка останова дебаггера
activityIndicator.stopAnimating() // Этот код не выполняется

Решение:

  1. Вызовите stopAnimating() при возобновлении работы приложения:
    NotificationCenter.default.addObserver(
        forName: UIApplication.didBecomeActiveNotification,
        object: nil,
        queue: .main
    ) { _ in
        activityIndicator.stopAnimating()
    }
  2. Используйте флаг для ручного управления состоянием в viewWillAppear/viewDidDisappear.

Ответ 18+ 🔞

А, ну это классика, блядь! Слушай, вот ты ставишь точку останова, приложение встаёт колом, а этот ёбаный крутилка-вертилка, сука, как ни в чём не бывало себе продолжает вертеться! Прямо как мартышлюшка заведённая, ей-богу.

Вот в чём, блядь, соль-то: эта анимация — она не в твоём коде живёт, а на системном уровне, в этом самом Core Animation. Там отдельный поток рендеринга, ему похуй, что у тебя в дебаггере главный поток встал. Он себе рисует кадры, как ни в чём не бывало. А твоя команда stopAnimating() — это просто флаг поставить и сказать слою: «Бро, перерисуйся уже без анимации». Но слой-то не может перерисоваться, пока главный поток, сука, висит на точке останова! Вот и получается, что вертушка крутится, а остановить её не получается — пиздец просто.

Смотри, как это выглядит в коде, тут всё просто:

activityIndicator.startAnimating()
// Тут ты ставишь брейкпоинт и всё стопаешь
activityIndicator.stopAnimating() // А эта строка, блядь, не выполняется! Вот в чём засада!

Как с этим бороться, чтобы не ебаться? Есть пара рабочих способов, на выбор.

  1. Слушать систему, как она проснулась. Когда приложение из бекграунда возвращается или дебаггер отпускает — лови момент и стопай анимацию.

    NotificationCenter.default.addObserver(
        forName: UIApplication.didBecomeActiveNotification,
        object: nil,
        queue: .main
    ) { _ in
        activityIndicator.stopAnimating() // Вот теперь-то ты, сука, остановишься!
    }
  2. Сам всё контролируй, как взрослый. В viewWillAppear и viewDidDisappear руками включай и выключай по флагу. Хуй запутаешься.

Короче, суть в том, что система живёт своей жизнью, а твой код — своей. Надо просто знать эту особенность и не париться, когда в дебаггере крутилка не останавливается. Это не баг, это фича, ёпта!