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

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

Ответ

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

Как обеспечить потокобезопасность:

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

    • Серийная очередь: Гарантирует последовательный доступ.
      
      let serialQueue = DispatchQueue(label: "com.example.serial")
      var array = [Int]()

    func addElement(_ element: Int) { serialQueue.async { array.append(element) } }

    *   **Concurrent очередь с барьером:** Позволяет параллельные чтения, но записи выполняются эксклюзивно.
    ```swift
    let concurrentQueue = DispatchQueue(label: "com.example.concurrent", attributes: .concurrent)
    var dictionary = [String: Int]()
    
    func setValue(_ value: Int, for key: String) {
        concurrentQueue.async(flags: .barrier) {
            dictionary[key] = value
        }
    }
  2. Использование примитивов синхронизации: NSLock, os_unfair_lock.

  3. Использование Actor (Swift 5.5+): Наиболее современный и рекомендуемый способ.

    actor SafeCounter {
        private var count = 0
    
        func increment() {
            count += 1
        }
    
        func getCount() -> Int {
            return count
        }
    }

Примечание: NSArray, NSDictionary в их неизменяемой (immutable) форме потокобезопасны, так как их состояние не может быть изменено после создания.