Из какого потока можно работать с UIView в iOS?

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

Ответ

Только из главного потока (Main Thread). UIKit не является потокобезопасным фреймворком. Обновление UI из фонового потока приводит к неопределённому поведению, крашам (EXC_BAD_ACCESS) или визуальным артефактам.

Почему? Все операции отрисовки и обработки пользовательского ввода координируются циклом событий (RunLoop) главного потока. Прямое изменение свойств UIView (например, frame, text, backgroundColor) из другого потока нарушает эту синхронизацию.

Как безопасно обновлять UI из фонового потока?

  1. Используйте DispatchQueue.main:

    DispatchQueue.global(qos: .background).async {
        // Выполняем фоновую задачу
        let result = heavyCalculation()
    
        DispatchQueue.main.async {
            // Обновляем UI с результатом
            self.label.text = result
            self.view.backgroundColor = .systemBlue
        }
    }
  2. Используйте @MainActor (Swift 5.5+): Аннотация гарантирует выполнение метода или свойства в главном потоке.

    @MainActor
    func updateUI() {
        label.text = "Updated"
    }
  3. Используйте UIScheduler (Combine): Для планирования работы издателя (Publisher) на главный поток.

    viewModel.$title
        .receive(on: DispatchQueue.main)
        .assign(to: .text, on: label)

Исключение: Некоторые операции, связанные с чтением (например, получение frame), могут работать в фоне, но это недокументированное поведение. Всегда придерживайтесь правила обновления UI только из главного потока.