Наиболее распространённый и безопасный способ в iOS.
class SafeContainer<T> {
private var storage = [T]()
private let accessQueue = DispatchQueue(label: "com.example.safe.storage", attributes: .serial)
func append(_ item: T) {
accessQueue.async {
self.storage.append(item)
}
}
var count: Int {
return accessQueue.sync {
storage.count
}
}
}
Преимущества:
Низкоуровневый, но эффективный механизм.
class ThreadSafeCounter {
private var count = 0
private var mutex = os_unfair_lock()
func increment() {
os_unfair_lock_lock(&mutex)
defer { os_unfair_lock_unlock(&mutex) }
count += 1
}
func currentValue() -> Int {
os_unfair_lock_lock(&mutex)
defer { os_unfair_lock_unlock(&mutex) }
return count
}
}
Кастомная property wrapper реализация.
@propertyWrapper
struct Atomic<Value> {
private var value: Value
private let lock = NSLock()
init(wrappedValue: Value) {
self.value = wrappedValue
}
var wrappedValue: Value {
get {
lock.lock()
defer { lock.unlock() }
return value
}
set {
lock.lock()
defer { lock.unlock() }
value = newValue
}
}
}
class SharedData {
@Atomic var counter = 0
}
Современный подход с языковой поддержкой.
actor BankAccount {
private var balance: Double = 0
func deposit(_ amount: Double) {
balance += amount
}
func withdraw(_ amount: Double) async throws -> Double {
guard balance >= amount else {
throw InsufficientFundsError()
}
balance -= amount
return amount
}
}
Оптимизация для частого чтения и редкой записи.
class DataCache {
private var cache = [String: Data]()
private let queue = DispatchQueue(label: "com.example.cache", attributes: .concurrent)
func set(data: Data, for key: String) {
queue.async(flags: .barrier) {
self.cache[key] = data
}
}
func get(for key: String) -> Data? {
return queue.sync {
cache[key]
}
}
}
Частота операций:
Производительность:
Сложность логики:
Поддержка Swift версий:
// ПЛОХО!
class UnsafeSingleton {
static let shared = UnsafeSingleton()
var counter = 0 // Не защищено!
}
var globalCounter = 0 // Опасная глобальная переменная
DispatchQueue.concurrentPerform(iterations: 100) { _ in
globalCounter += 1 // Race condition!
}
DispatchQueue.global().async {
self.label.text = "New" // Крах приложения!
}
Используйте value-типы:
Принцип изоляции:
Тестирование:
для безопасного доступа к переменным в iOS используйте либо серийные очереди (для Objective-C совместимости), либо акторы (в Swift 5.5+). Для критичных к производительности участков применяйте os_unfair_lock, а для сложных сценариев синхронизации - reader-writer паттерн. Всегда проверяйте многопоточный код с Thread Sanitizer.