Добавить объявление

Синглтоны в Swift Concurrency: как избежать гонки данных

Синглтоны - это классический паттерн, который есть почти в каждом iOS-проекте. Но в эпоху Swift Concurrency они превращаются в мину замедленного действия, потому что это глобальное состояние, доступное из любого потока.

Обычный синглтон - это класс, а классы в Swift по умолчанию не thread-safe (не потокобезопасны). Когда вы обращаетесь к синглтону из разных потоков или акторов, возможны гонки данных и непредсказуемое поведение.

Решение проблемы:


Есть несколько стратегий:

  • @MainActor:

    @MainActor
    class ThemeManager {
    static let shared = ThemeManager()
    private init() {}

    var currentTheme = "light"

    func switchToDarkTheme() {
    currentTheme = "dark"
    // Здесь обновляем UI
    }
    }

    Как это работает:

    - Гарантирует, что все обращения к синглтону будут на главном потоке.

    - Компилятор сам проверяет изоляцию.

    - Отлично подходит для синглтонов, которые влияют на интерфейс.

  • @unchecked Sendable:

    class CounterManager: @unchecked Sendable {
    static let shared = NetworkManager()
    private init() {}

    // Используем NSLock для потокобезопасности
    private let lock = NSLock()
    private var count = 0

    func increment() {
    lock.lock()
    count += 1
    print("Count: \(count)")
    lock.unlock()
    }
    }

    // Использование:
    CounterManager.shared.increment()

    Это вариант для случаев, когда вы вручную обеспечиваете потокобезопасность через NSLock или подобные инструменты.

Вывод:


Для большинства проектов @MainActor оказывается идеальным решением. Этот подход сочетает в себе простоту использования и надежную защиту от проблем с потоками.

Другие варианты вроде кастомных акторов или ручных блокировок часто создают больше сложностей, чем решают проблем. Они требуют постоянного использования await или тщательной ручной синхронизации, что лишает синглтоны их главного преимущества - простоты.
13.11.2025 10 496