Ответ
Нет. Стандартные коллекции 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.