【问题标题】:How do I synchronize access to a property that has didSet?如何同步对具有 didSet 的属性的访问?
【发布时间】:2017-05-17 05:05:26
【问题描述】:

如何同步对使用 didSet 的属性的访问(使用 GCD 或 objc_sync_enter)?

我有一个有属性观察者的属性。如何使用私有队列来同步获取/设置属性

var state: State = .disconnected {
  // Q: How to sync get/set access here?
  didSet {
    // do something
  }
}

【问题讨论】:

    标签: swift grand-central-dispatch synchronized


    【解决方案1】:

    最简单的方法是使用串行队列

    import Dispatch
    
    struct S {
        private var i: Int = 0 {
            didSet {
                print("someone did set new value:", i)
            }
        }
        private let queue = DispatchQueue(label: "private", qos: .userInteractive) // high priority
        var value: Int {
            get {
                return queue.sync {
                    return i
                }
            }
            set {
                if newValue == value {
                    return
                }
                queue.sync {
                    i = newValue
                }
            }
        }
    }
    

    更高级的示例使用并发读取和同步屏障进行写入

    import Dispatch
    
    struct S {
        private var i: Int = 0 {
            didSet {
                print("someone did set new value:", i)
            }
        }
        private let queue = DispatchQueue(label: "private", qos: .userInteractive, attributes: .concurrent) // high priority
        var value: Int {
            get {
                return queue.sync {
                    return i
                }
            }
            set {
                if newValue == value {
                    return
                }
                queue.sync(flags: .barrier) {
                    i = newValue
                }
            }
        }
    }
    

    在类属性的情况下,您可以使用并发私有队列并同时从不同线程读取并使用屏障异步调度写入

    import Dispatch
    
    class S {
        private var i: Int = 0 {
            didSet {
                print("someone did set new value:", i)
            }
        }
        private let queue = DispatchQueue(label: "private", qos: .userInteractive, attributes: .concurrent) // high priority
        var value: Int {
            get {
                return queue.sync {
                    return i
                }
            }
            set {
                if newValue == value {
                    return
                }
                queue.async(flags: .barrier) { [unowned self] in
                    self.i = newValue
                }
            }
        }
    }
    

    【讨论】:

    • 所以要强制同步我必须创建另一个计算属性?
    • @Boon 你必须“隔离”你的“私有”存储,所以使用计算属性似乎是一个合乎逻辑的步骤,不是吗?
    • @Boon 我不知道,你的使用场景到底是什么,但我强烈建议查看这篇精彩的阅读mikeash.com/pyblog/…
    • 你不应该在你的作家中使用[unowned self]async
    【解决方案2】:

    备用(使用 objc_sync_enter):

    class MyUtil {
    
      class func synchronize(_ blockObj: AnyObject!, closure: () -> Void) {
        objc_sync_enter(blockObj)
        closure()
        objc_sync_exit(blockObj)
      }
      class func synchronize<T>(_ blockObj: AnyObject!, closure: () -> T) -> T {
        objc_sync_enter(blockObj)
        let retVal:T = closure()
        objc_sync_exit(blockObj)
        return retVal
      }
    }
    
    struct S {
      private var i: Int = 0 {
        didSet {
            print("someone did set new value:", i)
        }
      }
      var value: Int {
        get {
            return MyUtil.synchronize(i as AnyObject) {
                return i
            }
        }
        set {
            MyUtil.synchronize(i as AnyObject) {
              if newValue == value {
                  return
              }
              i = newValue
            }
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-01-06
      • 1970-01-01
      • 2018-03-18
      • 1970-01-01
      • 2015-12-24
      • 1970-01-01
      相关资源
      最近更新 更多