![](/img/trans.png)
[英]DidEnterRegion only called if requestAlwaysAuthorization is called. Beacons
[英]PropertyWrapper subscript is not called. WHY?
我正在实现我自己的AtomicDictionary
属性包装器,如下所示:
@propertyWrapper
public class AtomicDictionary<Key: Hashable, Value>: CustomDebugStringConvertible {
public var wrappedValue = [Key: Value]()
private let queue = DispatchQueue(label: "atomicDictionary.\(UUID().uuidString)",
attributes: .concurrent)
public init() {}
public subscript(key: Key) -> Value? {
get {
queue.sync {
wrappedValue[key]
}
}
set {
queue.async(flags: .barrier) { [weak self] in
self?.wrappedValue[key] = newValue
}
}
}
public var debugDescription: String {
return wrappedValue.debugDescription
}
}
现在,当我按如下方式使用它时:
class ViewController: UIViewController {
@AtomicDictionary var a: [String: Int]
override func viewDidLoad() {
super.viewDidLoad()
self.a["key"] = 5
}
}
AtomicDicationary的下标AtomicDicationary
没有被调用!!
有人对为什么会这样有任何解释吗?
属性包装器只是为基本访问器方法提供一个接口,仅此而已。 它不会拦截下标或其他方法。
最初的属性包装提案SE-0258向我们展示了幕后发生的事情。 它考虑了一个假设的属性包装器Lazy
,其中:
财产申报
@Lazy var foo = 1738
翻译成:
private var _foo: Lazy<Int> = Lazy<Int>(wrappedValue: 1738) var foo: Int { get { return _foo.wrappedValue } set { _foo.wrappedValue = newValue } }
请注意, foo
只是一个Int
计算属性。 _foo
是Lazy<Int>
。
因此,在您a["key"] = 5
示例中,它不会使用您的属性包装器的下标运算符。 它将get
与a
关联的值,使用字典自己的下标运算符来更新该值(而不是属性包装器的下标运算符),然后它将set
与a
关联的值。
这就是属性包装器所做的全部工作,提供get
和set
访问器。 例如,声明:
@AtomicDictionary var a: [String: Int]
翻译成:
private var _a: AtomicDictionary<String, Int> = AtomicDictionary<String, Int>(wrappedValue: [:])
var a: [String: Int] {
get { return _a.wrappedValue }
set { _a.wrappedValue = newValue }
}
在此示例中,您定义的任何其他方法只能通过_a
访问,而不是a
(它只是一个计算属性,用于获取和设置_a
的wrappedValue
)。
所以,你最好只为你的“原子字典”定义一个合适的类型:
public class AtomicDictionary<Key: Hashable, Value> {
private var wrappedValue: [Key: Value]
private let queue = DispatchQueue(label: "atomicDictionary.\(UUID().uuidString)", attributes: .concurrent)
init(_ wrappedValue: [Key: Value] = [:]) {
self.wrappedValue = wrappedValue
}
public subscript(key: Key) -> Value? {
get {
queue.sync {
wrappedValue[key]
}
}
set {
queue.async(flags: .barrier) {
self.wrappedValue[key] = newValue
}
}
}
}
和
let a = AtomicDictionary<String, Int>()
这给了你你想要的行为。
如果您要提供CustomDebugStringConvertible
一致性,请确保也在那里使用您的同步机制:
extension AtomicDictionary: CustomDebugStringConvertible {
public var debugDescription: String {
queue.sync { wrappedValue.debugDescription }
}
}
与包装值的所有交互都必须同步。
显然,您可以将这种通用模式与您想要的任何同步机制一起使用,例如,上面的读写器模式、GCD 串行队列、锁、参与者等。(读写器模式具有天然的吸引力,但在实践中,通常是更好的机制。)
不用说,上面假设下标级原子性就足够了。 人们应该始终警惕通用线程安全 collections,因为我们代码的正确性通常依赖于更高级别的同步。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.