如何同步访问具有didSet的属性?

3

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

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

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

4

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

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 你需要“隔离”你的“私有”存储,所以使用计算属性似乎是一个合理的步骤,不是吗? - user3441734
@Boon 我不知道你的具体使用场景是什么,但我强烈建议你阅读这篇很好的文章:https://www.mikeash.com/pyblog/friday-qa-2015-02-06-locks-thread-safety-and-swift.html - user3441734
在编写代码时,不应该在async中使用[unowned self] - Rob

0

备用方案(使用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
        }
    }
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接