Ответ
Нет, напрямую к переменной — нельзя. Ключевое слово @synchronized из Objective-C (и аналогичные механизмы) применяются к блокам кода или методам, чтобы сделать их потокобезопасными, а не к самим переменным.
Правильный подход — синхронизировать доступ к переменной:
-
Использование
NSLock(наиболее прямой аналог@synchronized):let lock = NSLock() var sharedCounter = 0 func increment() { lock.lock() defer { lock.unlock() } // Гарантирует разблокировку sharedCounter += 1 } -
Использование serial
DispatchQueue(предпочтительный способ в Swift):let serialQueue = DispatchQueue(label: "com.app.serialQueue") var sharedData: [String] = [] func appendData(_ value: String) { serialQueue.sync { // Все операции на этой очереди выполняются последовательно sharedData.append(value) } } -
Использование
os_unfair_lock(более производительный, но требующий аккуратности):var unfairLock = os_unfair_lock() var resource: Int = 0 os_unfair_lock_lock(&unfairLock) resource = 42 os_unfair_lock_unlock(&unfairLock)
Вывод: Синхронизируется не переменная, а критическая секция — участок кода, где происходит чтение или запись этой переменной из нескольких потоков.
Ответ 18+ 🔞
О, слушай, смотри, вот тут у людей иногда мозг сносит на раз-два. Хотят взять и навесить @synchronized прямо на переменную, как брелок на ключи. Типа, объявил — и всё, потокобезопасно, можно спать спокойно.
Да хуй там плавал, ёпта! Это же не магический амулет, который ты на шею объекту вешаешь. Это механизм, который работает с кодом, с участками, где эта самая переменная меняется или читается. Критическими секциями, блядь, называются.
Представь себе сортир на вокзале. Дверь — это твоя переменная sharedCounter. А @synchronized или NSLock — это не табличка «не влезай, убьёт» на самой двери. Это здоровенный верзила-охранник, который стоит рядом и говорит: «Очередь, сука, на хуй! Заходить по одному!». Он контролирует процесс захода-выхода (чтения-записи), а не саму дверь.
Вот смотри, как это по-свифтовски, правильно и без этих обёрток Objective-C делается:
Вариант 1 — Охранник с дубинкой (NSLock). Прямой, тупой и эффективный.
let lock = NSLock() // Наш верзила
var sharedCounter = 0 // Наша дверь в сортир
func increment() {
lock.lock() // Верзила говорит: "Стоять, блядь! Ты следующий."
defer { lock.unlock() } // Это гениально. Гарантия, что даже если тебя внутри трамвай переедет, он дверь откроет.
sharedCounter += 1 // Ты делаешь свои дела.
}
Вариант 2 — Умная очередь (DispatchQueue). Цивилизованно, по-европейски.
let serialQueue = DispatchQueue(label: "com.myapp.dataQueue") // Организованная очередь, как в банке.
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) // Отпустил. Главное — не забыть, а то задушишь поток нахуй.
Так что запомни, как «Отче наш»: синхронизируется не переменная, а действия с ней. Участок кода, где к ней прикасаются из разных потоков. Всё остальное — это пиздёж и провокация, ведущая к гонкам, крешам и ночным бдениям с отладчиком. Чистый изумруд, блядь!