Ответ
Нет. Стандартные коллекции 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.
Ответ 18+ 🔞
А, слушай, вот этот вопрос про коллекции в Swift — он как гнойник на заднице, блядь, который рано или поздно придётся вскрывать. Все эти твои Array, Dictionary — они же, сука, как голые младенцы в толпе пьяных матросов, если их в несколько потоков пинать начинаешь. Один пишет, другой читает — и пиздец, приложение крашнется так, что мало не покажется, в рот меня чих-пых!
Ну ладно, не буду тебя пугать, как бабушка в подъезде. Давай по делу, как взрослые люди, блядь.
Способы, чтобы эту шалаву — многопоточность — приструнить:
1. GCD с этим самым... барьером, блядь!
Это как поставить здорового мужика с дубиной у входа в сортир. Хочешь пописАть — иди, хуле. Хочешь насрать — все, блядь, ждут, пока ты свой процесс завершишь. Никто не вломится в момент свершения.
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 — классика, ёпта!
Прям как старый дедовский амбарный замок. Пришёл, щёлк — закрыл, сделал свои делишки, щёлк — открыл. Проще некуда, но если забудешь открыть — все, пидарас, deadlock, и все будут стоять и ждать, пока ты сдохнешь.
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. Акторы (Swift 5.5+) — это, сука, будущее наступило!
Это уже не замок, это целая система безопасности уровня президента. Компилятор сам, блядь, следит, чтобы к твоим данным в один момент времени только один поток имел доступ. Красота, ёперный театр!
actor SafeCollection { // Видишь это слово `actor`? Всё, пиздец гонкам данных!
private var items = [String]()
func add(_ item: String) {
items.append(item)
}
func getAll() -> [String] {
return items
}
}
// Использовать — только с `await`, блядь. Терпения, сука, наберись.
// await safeCollection.add("item")
Итог, блядь, короткий:
Если пишешь на свежем Swift — бери акторы и не еби себе мозг.
Если ковыряешь старый код, который видел виды — GCD с барьером твой друг.
А NSLock — это как молоток: иногда без него никуда, но можно и по пальцам получить, если неаккуратно.
Вот и вся философия, блядь. Не усложняй.