Ответ
Потому что UIKit и SwiftUI не являются потокобезопасными. Все операции с пользовательским интерфейсом должны выполняться на главном потоке (main thread). Нарушение этого правила приводит к:
- Неожиданным крашам (часто с ошибкой
Main Thread Checker). - Визуальным артефактам и задержкам отрисовки.
- Непредсказуемому поведению элементов интерфейса.
Правильный паттерн:
// 1. Выполняем тяжелую работу в фоне
DispatchQueue.global(qos: .userInitiated).async {
let processedImage = self.applyFilters(to: originalImage)
// 2. Возвращаемся на главный поток для обновления UI
DispatchQueue.main.async {
self.imageView.image = processedImage
self.activityIndicator.stopAnimating()
}
}
SwiftUI (автоматическое управление):
Task {
// Автоматически выполняется в фоновом потоке
let data = await fetchData()
// Обновление @Published/@State свойств автоматически
// переносится на главный поток
self.items = data
}
Исключения (но с осторожностью):
- Создание
UIImage(data:)из фонового потока допустимо, но установка вUIImageView— только на главном. - Некоторые вычисления layout (например,
sizeThatFits) могут работать в фоне, если не обращаются к UI-иерархии.
Проверка текущего потока:
assert(Thread.isMainThread, "Этот код должен выполняться на главном потоке!")