Какие механизмы синхронизации существуют в iOS
Что проверяют
Умеете ли вы защитить общее состояние и выбрать инструмент под задачу, а не просто перечислить API. Следом почти всегда просят показать, где тут может случиться дедлок, и чем actor отличается от очереди с блокировкой.
Как отвечать
Разделите механизмы на три группы: взаимное исключение, координация задач и модель Swift Concurrency.
- последовательная
DispatchQueue: все обращения к состоянию идут через одну очередь, порядок гарантирован. Для схемы «много читателей, один писатель» берут конкурентную очередь и запись черезasync(flags: .barrier); - блокировки:
NSLock,NSRecursiveLock,NSConditionи самая быстраяos_unfair_lock. В Swift её безопасно использовать черезOSAllocatedUnfairLock(iOS 16+), а с iOS 18 естьMutexиAtomicиз модуляSynchronization; DispatchSemaphore: ограничивает число одновременных доступов к ресурсу, например не больше трёх загрузок сразу;DispatchGroupи зависимостиOperation: данные не защищают, а ждут завершения набора задач.OperationQueueсmaxConcurrentOperationCount = 1работает как последовательная очередь;actorи@MainActor: компилятор не пускает к изолированному состоянию снаружи безawait, а в режиме Swift 6 гонки данных ловятся ещё на сборке через проверкуSendable.
Итог сформулируйте так: в новом коде по умолчанию actor, блокировку оставляют для короткой синхронной критической секции, где await неуместен. Упомяните Thread Sanitizer как способ найти гонку, которую глазами не видно.
Где спотыкаются
Называют atomic в Objective-C защитой от гонок. Он гарантирует только целостность одного чтения или записи свойства, а count += 1 остаётся гонкой.
Вызывают DispatchQueue.main.sync с главного потока или блокируют семафором поток внутри async-функции. Первое это гарантированная взаимная блокировка, второе может исчерпать ограниченный пул потоков Swift Concurrency.
Считают actor полностью последовательным. Он реентерабелен: на каждом await другие вызовы успевают изменить его состояние, поэтому проверку и изменение нельзя разрывать ожиданием.