🚨 Swift 6 и Singleton: что изменилось?
С выходом Swift 6 включается строгая проверка конкурентности (strict concurrency checking). Это значит, что:
✅ Раньше: ты мог использовать синглтон из любого потока — компилятор лишь предупреждал
❌ Теперь: компилятор выдаёт ошибку, если твой синглтон не потокобезопасен
🧱 Почему это важно?
Синглтоны обычно создаются так:
Этот shared может быть вызван из разных потоков, и без защиты от одновременного доступа это вызывает data races.
✅ Как сделать синглтон безопасным в Swift 6
1. actor — идеальный способ для полной изоляции
🔐 Все вызовы методов внутри actor автоматически сериализуются — то есть выполняются по одному, без гонок данных.
2. @MainActor — когда синглтон работает только на main thread
🎯 Используется для ViewModel, NavigationCoordinator, ThemeManager — всего, что связано с UI.
3. Sendable + ручная защита или let-поля
🧊 Хорошо для конфигураций, флагов, настроек и других объектов, которые не изменяются.
⚠ Плохой пример (так больше нельзя в Swift 6)
🔴 В Swift 6 это вызовет ошибку компиляции, если вызвать shared.increment() из разных actor-контекстов.
💬 Какой способ выбрать?
- Если работа связана с UI, например ViewModel, темы, навигация — используй @MainActor. Это гарантирует, что всё выполняется на главном потоке.
- Если у тебя логгеры, сетевые сервисы или менеджеры, которые могут вызываться из разных потоков — используй actor. Это обеспечит безопасную конкурентную изоляцию.
- Если твой синглтон — это просто конфигурация, флаги или другие неизменяемые данные, используй Sendable и сделай все свойства let.
- Если у тебя старый код, и ты пока не хочешь/не можешь его переделать, можно временно использовать @unchecked Sendable. Но это не рекомендуется — лучше всё же адаптировать под новый подход.
🚀 Заключение
Swift 6 не убивает Singleton — он делает его безопасным. Если у тебя в проекте есть shared, проверь, защищён ли он. Это легко исправить — и компилятор поможет тебе.