Почему операции с UIStackView должны выполняться на главном потоке?

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

Ответ

UIStackView, как и любой другой компонент UIKit, не является потокобезопасным. Все манипуляции с его свойствами и иерархией вложенных представлений (addArrangedSubview, removeArrangedSubview, изменение axis, spacing и т.д.) должны выполняться строго на главной потоке (Main Thread).

Причина: UIKit внутренне использует небезопасные для многопоточности структуры данных. Параллельные изменения из нескольких потоков приводят к неопределенному поведению и крашам.

Правильный подход: Все обновления UI должны быть обернуты в вызов DispatchQueue.main.

// Фоновый поток (например, после сетевого запроса)
DispatchQueue.global(qos: .background).async {
    let newView = UIView()
    // ... настройка newView

    // НЕПРАВИЛЬНО - вызовет краш или неопределенное поведение
    // self.stackView.addArrangedSubview(newView)

    // ПРАВИЛЬНО - переход на главный поток
    DispatchQueue.main.async {
        self.stackView.addArrangedSubview(newView)
        // Любые другие обновления UIStackView
    }
}

Как проверить поток? Используйте Thread.isMainThread для отладки.

if Thread.isMainThread {
    stackView.isHidden = true
} else {
    DispatchQueue.main.async { [weak self] in
        self?.stackView.isHidden = true
    }
}

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