【问题标题】:Simultaneous accesses when using PropertyWrapper使用 PropertyWrapper 时的同时访问
【发布时间】:2019-12-13 07:25:29
【问题描述】:

我想创建一个property wrapper,它会存储一个callback block,并在每次值发生变化时执行它。类似简单的KVO。它工作正常,但有一个问题。如果我在此回调块中使用属性本身,则会收到错误消息:

Simultaneous accesses to 0x6000007fc3d0, but modification requires exclusive access

据我了解,这是因为属性本​​身仍在被写入,而该块正在执行,这就是它无法读取的原因。

让我们添加一些代码来说明我的意思:

@propertyWrapper
struct ReactingProperty<T> {

    init(wrappedValue: T) {
        self.wrappedValue = wrappedValue
    }

    public var wrappedValue: T {
        didSet {
            reaction?(wrappedValue)
        }
    }

    public var projectedValue: Self {
        get { self }
        set { self = newValue }
    }

    private var reaction: ((_ value: T) -> Void)?

    public mutating func setupReaction(_ reaction: @escaping (_ value: T) -> Void) {
        self.reaction = reaction
    }

}

还有AppDelegate:

@UIApplicationMain
class AppDelegate: UIResponder, UIApplicationDelegate {

    @ReactingProperty
    var testInt = 0

    func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
        // Override point for customization after application launch.

        // 1. This will pass correctly.

        $testInt.setupReaction { (value) in
            print(value)
        }

        testInt = 1

        // 2. This will cause crash, because I access testInt in this block, that is executed when value changes.

        $testInt.setupReaction { [unowned self] (value) in
            print(self.testInt)
        }

        testInt = 2

        return true
    }

}

我有一些解决方法,但由于各种原因,没有一个主题是我真正需要的。

  1. 如果我改为从这个block argument 访问block 中的值,并将这个参数传递给值didSet,那么它工作正常。但这迫使我总是以这种方式使用它,我想将它与包含各种其他回调的代码一起使用,有时我也能够直接访问这个值会更方便。

  2. 我可以异步执行callback block (DispachQueue.main.async { self.block?(value) })。但这对我来说也不是最好的。

  3. 请改用combine。我可能会,但我也想暂时保留这个功能。我也只是对这个问题感到好奇。

这可以通过某种方式克服吗?什么变量实际上导致了这个read-write 访问错误?这是propertyWrapper 内部的值还是带有propertyWrapper 本身的结构? 我认为是propertyWrapper struct 访问导致了这种情况,而不是它的内部价值,但我不确定。

【问题讨论】:

    标签: ios swift thread-safety read-write property-wrapper


    【解决方案1】:

    我想我找到了正确的解决方案。只需从结构更改为类。那么读/写访问就没有问题了。

    @propertyWrapper
    class ReactingProperty<T> {
    
        init(wrappedValue: T) {
            self.wrappedValue = wrappedValue
        }
    
        public var wrappedValue: T {
            didSet {
                reaction?(wrappedValue)
            }
        }
    
        public lazy var projectedValue = self
    
        private var reaction: ((_ value: T) -> Void)?
    
        public mutating func setupReaction(_ reaction: @escaping (_ value: T) -> Void) {
            self.reaction = reaction
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-06-15
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多