Можно ли в iOS применить synchronized напрямую к переменной?

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

Ответ

Нет, напрямую к переменной — нельзя. Ключевое слово @synchronized из Objective-C (и аналогичные механизмы) применяются к блокам кода или методам, чтобы сделать их потокобезопасными, а не к самим переменным.

Правильный подход — синхронизировать доступ к переменной:

  1. Использование NSLock (наиболее прямой аналог @synchronized):

    let lock = NSLock()
    var sharedCounter = 0
    
    func increment() {
        lock.lock()
        defer { lock.unlock() } // Гарантирует разблокировку
        sharedCounter += 1
    }
  2. Использование serial DispatchQueue (предпочтительный способ в Swift):

    let serialQueue = DispatchQueue(label: "com.app.serialQueue")
    var sharedData: [String] = []
    
    func appendData(_ value: String) {
        serialQueue.sync { // Все операции на этой очереди выполняются последовательно
            sharedData.append(value)
        }
    }
  3. Использование os_unfair_lock (более производительный, но требующий аккуратности):

    var unfairLock = os_unfair_lock()
    var resource: Int = 0
    
    os_unfair_lock_lock(&unfairLock)
    resource = 42
    os_unfair_lock_unlock(&unfairLock)

Вывод: Синхронизируется не переменная, а критическая секция — участок кода, где происходит чтение или запись этой переменной из нескольких потоков.