[英]PropertyWrapper subscript is not called. WHY?
I am implementing my own AtomicDictionary
property wrapper as follows:我正在实现我自己的
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
}
}
now, when I use it as follows:现在,当我按如下方式使用它时:
class ViewController: UIViewController {
@AtomicDictionary var a: [String: Int]
override func viewDidLoad() {
super.viewDidLoad()
self.a["key"] = 5
}
}
The subscript function of the AtomicDicationary
is not called!! AtomicDicationary的下标
AtomicDicationary
没有被调用!!
Does anybody have any explanation as to why that is?有人对为什么会这样有任何解释吗?
Property wrappers merely provide an interface for the basic accessor methods, but that's it. 属性包装器只是为基本访问器方法提供一个接口,仅此而已。 It's not going to intercept subscripts or other methods.
它不会拦截下标或其他方法。
The original property wrapper proposal SE-0258 shows us what is going on behind the scenes.最初的属性包装提案SE-0258向我们展示了幕后发生的事情。 It contemplates a hypothetical property wrapper,
Lazy
, in which:它考虑了一个假设的属性包装器
Lazy
,其中:
The property declaration
财产申报
@Lazy var foo = 1738
translates to:
翻译成:
private var _foo: Lazy<Int> = Lazy<Int>(wrappedValue: 1738) var foo: Int { get { return _foo.wrappedValue } set { _foo.wrappedValue = newValue } }
Note that foo
is just an Int
computed property.请注意,
foo
只是一个Int
计算属性。 The _foo
is the Lazy<Int>
. _foo
是Lazy<Int>
。
So, in your a["key"] = 5
example, it will not use your property wrapper's subscript operator.因此,在您
a["key"] = 5
示例中,它不会使用您的属性包装器的下标运算符。 It will get
the value associated with a
, use the dictionary's own subscript operator to update that value (not the property wrapper's subscript operator), and then it will set
the value associated with a
.它将
get
与a
关联的值,使用字典自己的下标运算符来更新该值(而不是属性包装器的下标运算符),然后它将set
与a
关联的值。
That's all the property wrapper is doing, providing the get
and set
accessors.这就是属性包装器所做的全部工作,提供
get
和set
访问器。 Eg, the declaration:例如,声明:
@AtomicDictionary var a: [String: Int]
translates to:翻译成:
private var _a: AtomicDictionary<String, Int> = AtomicDictionary<String, Int>(wrappedValue: [:])
var a: [String: Int] {
get { return _a.wrappedValue }
set { _a.wrappedValue = newValue }
}
Any other methods you define are only accessible through _a
in this example, not a
(which is just a computed property that gets and sets the wrappedValue
of _a
).在此示例中,您定义的任何其他方法只能通过
_a
访问,而不是a
(它只是一个计算属性,用于获取和设置_a
的wrappedValue
)。
So, you're better off just defining a proper type for your “atomic dictionary”:所以,你最好只为你的“原子字典”定义一个合适的类型:
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
}
}
}
}
And和
let a = AtomicDictionary<String, Int>()
That gives you the behavior you want.这给了你你想要的行为。
And if you are going to supply CustomDebugStringConvertible
conformance, make sure to use your synchronization mechanism there, too:如果您要提供
CustomDebugStringConvertible
一致性,请确保也在那里使用您的同步机制:
extension AtomicDictionary: CustomDebugStringConvertible {
public var debugDescription: String {
queue.sync { wrappedValue.debugDescription }
}
}
All interaction with the wrapped value must be synchronized.与包装值的所有交互都必须同步。
Obviously you can use this general pattern with whatever synchronization mechanism you want, eg, the above reader-writer pattern, GCD serial queue, locks, actors, etc. (The reader-writer pattern has a natural appeal, but, in practice, there are generally better mechanisms.)显然,您可以将这种通用模式与您想要的任何同步机制一起使用,例如,上面的读写器模式、GCD 串行队列、锁、参与者等。(读写器模式具有天然的吸引力,但在实践中,通常是更好的机制。)
Needless to say, the above presumes that subscript-level atomicity is sufficient.不用说,上面假设下标级原子性就足够了。 One should always be wary about general purpose thread-safe collections as often the correctness of our code relies on a higher-level of synchronization.
人们应该始终警惕通用线程安全 collections,因为我们代码的正确性通常依赖于更高级别的同步。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.