You*_*mza 8 ios swift ios-multithreading swift-structs property-wrapper
我在 Swift 中创建了一个“锁”,并为我的 Swift 类创建了一个使用该锁的 Atomic 属性包装器,因为 Swift 缺少 ObjC 的atomic属性属性。
当我在启用线程清理器的情况下运行我的测试时,它总是捕获使用我的 Atomic 属性包装器的属性上的数据竞争。
唯一有效的是将属性包装器的声明更改为一个类而不是一个结构体,这里的主要问题是:为什么它有效!
我print在属性包装器中添加了s 并添加了 lockinit来跟踪创建的对象数量,它与 struct/class 相同,尝试在另一个项目中重现该问题,但也没有用。但是我会添加与问题类似的文件,并让我知道它为什么起作用的任何猜测。
锁
public class SwiftLock {
init() { }
public func sync<R>(execute: () throws -> R) rethrows -> R {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
return try execute()
}
}
Run Code Online (Sandbox Code Playgroud)
原子属性包装器
@propertyWrapper struct Atomic<Value> {
let lock: SwiftLock
var value: Value
init(wrappedValue: Value, lock: SwiftLock=SwiftLock()) {
self.value = wrappedValue
self.lock = lock
}
var wrappedValue: Value {
get {
lock.sync { value }
}
set {
lock.sync { value = newValue }
}
}
}
Run Code Online (Sandbox Code Playgroud)
模型(数据竞争应该发生在publicVariable2此处的属性上)
class Model {
@Atomic var publicVariable: TimeInterval = 0
@Atomic var publicVariable2: TimeInterval = 0
var sessionDuration: TimeInterval {
min(0, publicVariable - publicVariable2)
}
}
Run Code Online (Sandbox Code Playgroud)
更新 1: 完整的 Xcode 项目:https : //drive.google.com/file/d/1IfAsOdHKOqfuOp-pSlP75FLF32iVraru/view ? usp =sharing
此 PR 中回答了这个问题:https ://github.com/apple/swift-evolution/pull/1387
我认为这才是真正解释它的那些话
在 Swift 的正式内存访问模型中,值类型上的方法被视为访问整个值,因此调用wrappedValue getter 会正式读取整个存储的包装器,而调用wrappedValue 的setter 会正式修改整个存储的包装器。
包装器的值将在调用之前加载
wrappedValue.getter并在调用之后写回wrappedValue.setter。因此,包装器内的同步无法提供对其自身值的原子访问。