Вопрос проверяет понимание потокобезопасности lazy-свойств в Swift и их поведения в многопоточной среде.
Ключевое слово lazy в Swift позволяет отложить инициализацию свойства до момента его первого использования. Это полезно для оптимизации, когда создание ресурса дорого или зависит от других, ещё не готовых данных. Однако, стандартная реализация lazy var не гарантирует атомарность при одновременном доступе из нескольких потоков.
Механизм отложенной инициализации внутри себя использует флаг для отслеживания состояния. Если два потока одновременно проверят, что свойство ещё не инициализировано, оба могут запустить код инициализации, что может привести к:
class DataManager {
lazy var expensiveResource: String = {
// Дорогая операция, например, чтение файла
print("Инициализация ресурса")
return "Данные"
}()
}
let manager = DataManager()
DispatchQueue.concurrentPerform(iterations: 5) { _ in
_ = manager.expensiveResource // Может напечатать "Инициализация ресурса" несколько раз
}1. Использование dispatch_once (устарел в Swift, но возможен через Objective-C runtime).
2. Синхронизация с помощью DispatchQueue или NSLock.
3. Обёртка с атомарным доступом (например, кастомное свойство @Atomic).
4. Использование акторов (actors) в Swift Concurrency для изоляции состояния.
import Foundation
@propertyWrapper
struct AtomicLazy {
private var storage: T?
private let lock = NSLock()
private let initializer: () -> T
init(wrappedValue initializer: @escaping @autoclosure () -> T) {
self.initializer = initializer
}
var wrappedValue: T {
get {
lock.lock()
defer { lock.unlock() }
if storage == nil {
storage = initializer()
}
return storage!
}
}
}
class SafeDataManager {
@AtomicLazy var expensiveResource: String = {
print("Потокобезопасная инициализация")
return "Данные"
}()
}Вывод: Используйте стандартный lazy var только в однопоточном контексте или когда вы уверены, что первое обращение произойдёт до создания других потоков. В многопоточных приложениях, таких как iOS/macOS приложения с UI и фоновыми задачами, обязательно добавляйте синхронизацию для lazy-свойств, к которым возможен конкурентный доступ.