Являются ли стандартные коллекции Swift потокобезопасными?

«Являются ли стандартные коллекции Swift потокобезопасными?» — вопрос из категории Многопоточность, который задают на 10% собеседований IOS Разработчик. Ниже — развёрнутый ответ с разбором ключевых моментов.

Ответ

Нет. Стандартные коллекции Swift (Array, Dictionary, Set) не являются потокобезопасными (not thread-safe). Одновременный доступ на запись или одновременный доступ на чтение и запись из разных потоков приводит к гонкам данных (data races) и неопределённому поведению, включая краши.

Способы обеспечения потокобезопасности:

1. Использование GCD (Grand Central Dispatch) с барьером

Идеально для создания синхронизированной обёртки.

class ThreadSafeArray<Element> {
    private var array = [Element]()
    private let queue = DispatchQueue(label: "com.example.threadSafeArray", attributes: .concurrent)

    func append(_ element: Element) {
        queue.async(flags: .barrier) { // Барьер для записи
            self.array.append(element)
        }
    }

    var first: Element? {
        var result: Element?
        queue.sync { // Без барьера для чтения
            result = array.first
        }
        return result
    }
}

2. Использование NSLock или NSRecursiveLock

Простой подход для низкоуровневой синхронизации.

class LockedDictionary<Key: Hashable, Value> {
    private var dict = [Key: Value]()
    private let lock = NSLock()

    func set(value: Value, for key: Key) {
        lock.lock()
        defer { lock.unlock() }
        dict[key] = value
    }
}

3. Использование акторов (Actors, Swift 5.5+)

Наиболее современный и безопасный способ, гарантированный компилятором.

actor SafeCollection {
    private var items = [String]()

    func add(_ item: String) {
        items.append(item)
    }

    func getAll() -> [String] {
        return items
    }
}
// Использование: await safeCollection.add("item")

Рекомендация: Для новых проектов на Swift 5.5+ предпочтительно использовать акторы. Для поддержки legacy-кода — GCD с барьерами или locks.