Ответ
Нет, все изменения Auto Layout констрейнтов должны выполняться на главном потоке (main thread). UIKit не является потокобезопасным, и нарушение этого правила приводит к неопределённому поведению или крешам.
Правильный подход:
// Обновление констрейнтов на главном потоке
DispatchQueue.main.async {
view.widthAnchor.constraint(equalToConstant: 100).isActive = true
view.heightAnchor.constraint(equalToConstant: 200).isActive = true
// Принудительное обновление layout, если нужно
self.view.layoutIfNeeded()
}
Что можно делать в фоновом потоке:
- Вычисление размеров с помощью
systemLayoutSizeFitting() - Подготовка данных для констрейнтов
- Создание NSLayoutConstraint объектов (но не их активация)
Почему это важно:
- UIKit обрабатывает все обновления интерфейса в run loop главного потока
- Конкурентный доступ к слоям (CALayer) вызывает race conditions
- Auto Layout engine не синхронизирован для многопоточного доступа
Ответ 18+ 🔞
О, слушай, смотри, тут такая история, блядь. Все эти ваши констрейнты, Auto Layout — это как тонкая нервная система у интерфейса, понимаешь? И управлять ею можно только из одной, главной комнаты управления. С балкона, с кухни, из туалета — нихуя не получится, только с центрального пульта!
Вот представь: твой UI — это как ёбаный оркестр. А главный поток — это дирижёр, сука. И если каждый музыкант начнёт сам по себе пиликать, когда ему вздумается, из-за кулис, из подсобки — получится не музыка, а пиздец, блядь, какофония. Приложение просто накроется медным тазом, и все, концерт окончен.
Так вот, все команды типа «эй, видят, стань шириной в 100 пикселей» или «подрости до 200» — это прямые указания дирижёру. И давать их нужно, только когда ты стоишь прямо перед ним, на главном потоке, а не кричишь из-за двери, пока он с другим элементом разбирается.
// Делай вот так, по-человечески, на главной сцене
DispatchQueue.main.async {
view.widthAnchor.constraint(equalToConstant: 100).isActive = true
view.heightAnchor.constraint(equalToConstant: 200).isActive = true
// А если совсем припёрло, чтобы сразу всё встало как надо
self.view.layoutIfNeeded()
}
А то некоторые думают: «ой, да ёбта, я тут в фоне быстренько констрейнт создам, ничего же не происходит». Создать-то создашь, объект в памяти повисит. Но активировать его, впендюрить в живую иерархию вьюх — это уже действие, блядь. Это как взять и прилепить новую руку манекену прямо на складе, пока его несут на витрину. Рука, может, и приклеится, а манекен — хуй знает куда упадёт.
Чем можно заниматься в подполье, в фоновом потоке?
Ну, например, прикидывать, каких размеров всему этому безобразию быть, с помощью systemLayoutSizeFitting(). Или данные для этих размеров приготовить. Создать сами объекты NSLayoutConstraint — тоже можно, они же пока просто бумажки с планом. Но вот команду «исполнить!» — отдаёшь только главному дирижёру.
А почему, блядь, так строго?
- Весь UIKit — это один большой, сложный, ёбаный механизм, который тикает в такт главному циклу. Подкручивать шестерёнки на ходу, когда он работает, — это прямой путь в креш-логи, в рот меня чих-пых.
- Все эти слои,
CALayer— они как общаги, где живут пиксели. Если с разных потоков начать туда-сюда мебель двигать, они друг другу ноги оттопчут, race condition наступит, и всё посыпется. - Движок Auto Layout — он не учился работать с многопоточностью. Он один, и он скромный. Не надо его насиловать одновременными запросами из всех щелей.
Короче, запомни, как «Отче наш»: всё, что касается внешнего вида, обновляется ТОЛЬКО на главном потоке. Не хочешь охуенных багов и мистических падений — соблюдай правило, чувак.