Что произойдет при обновлении UI не на главном потоке в iOS?

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

Ответ

Обновление UI не на главном потоке приводит к неопределенному поведению:

  • Визуальные артефакты и мерцание
  • Зависания интерфейса
  • Аварийные завершения (чаще в Debug-сборках)
  • Несинхронное отображение данных

Почему UIKit требует главный поток:

  1. UIKit не является потокобезопасным
  2. Все UI-объекты имеют внутреннее состояние, которое должно изменяться атомарно
  3. Система рендеринга работает синхронно с основным run loop

❌ Опасный код:

DispatchQueue.global(qos: .background).async {
    // Фоновая загрузка данных
    let newData = loadDataFromNetwork()

    // ОПАСНО: обновление UI не на главном потоке
    self.tableView.reloadData()
    self.label.text = "Загружено: (newData.count) элементов"
    self.progressView.progress = 1.0
}

✅ Правильный подход:

DispatchQueue.global(qos: .background).async {
    // Фоновая работа
    let newData = loadDataFromNetwork()
    let image = processImage()

    // Возвращаемся на главный поток для UI
    DispatchQueue.main.async {
        self.data = newData
        self.tableView.reloadData()
        self.imageView.image = image
        self.updateUI()
    }
}

Особенности:

  • Main Thread Checker в Xcode обнаруживает такие ошибки
  • В iOS 16+ некоторые UIView-методы стали потокобезопасными, но это исключение
  • @MainActor в Swift помогает обеспечить выполнение на главном потоке:
    @MainActor
    func updateUI() {
    // Компилятор гарантирует выполнение на главном потоке
    label.text = "Обновлено"
    }

Правило: Все, что изменяет визуальное состояние (текст, цвет, позиция, анимация), должно выполняться на главном потоке.