How do I synchronize access to a property that has didSet?

末鹿安然 提交于 2019-12-12 18:08:38

问题


How do I synchronize access of a property that uses didSet (using GCD or objc_sync_enter)?

I have a property that has a property observer. How can I use a private queue to synchronize get/set of the property

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

回答1:


simplest way is using a serial queue

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
            }
        }
    }
}

more advanced example use concurrent reading and sync barrier for writing

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
            }
        }
    }
}

in the case of class property, you can use a concurrent private queue and read from different thread concurrently and dispatch write asynchronously with a barrier

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
            }
        }
    }
}



回答2:


Alternate (using 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
        }
    }
}


来源:https://stackoverflow.com/questions/44016028/how-do-i-synchronize-access-to-a-property-that-has-didset

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!