简体   繁体   English

不调用 PropertyWrapper 下标。 为什么?

[英]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> . _fooLazy<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 .它将geta关联的值,使用字典自己的下标运算符来更新该值(而不是属性包装器的下标运算符),然后它将seta关联的值。

That's all the property wrapper is doing, providing the get and set accessors.这就是属性包装器所做的全部工作,提供getset访问器。 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 (它只是一个计算属性,用于获取和设置_awrappedValue )。


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.

相关问题 仅在调用requestAlwaysAuthorization时才调用DidEnterRegion。 信标 - DidEnterRegion only called if requestAlwaysAuthorization is called. Beacons deinit 没有被调用。 帮我解决这个问题 - deinit is not being called. Help me fix this SwiftUI 中的@propertywrapper - @propertywrapper in SwiftUI UserNotifications扩展服务UNNotificationAction didReceive操作委托未被调用。 - UserNotifications Extension Service UNNotificationAction didReceive action delegate not getting called. 未调用UITableView委托方法。 从另一个类创建 - UITableView delegate methods not being called. Created from another class 未调用iOS 10 UNUserNotificationCenterDelegate。 推送通知无效 - iOS 10 UNUserNotificationCenterDelegate not called. push notifications not working @propertyDelegate和@propertyWrapper之间的区别 - Difference between @propertyDelegate and @propertyWrapper SwiftUI State PropertyWrapper 行为 - SwiftUI State PropertyWrapper Behavior 从 JSON 解码到 PropertyWrapper - Decode to PropertyWrapper from JSON 应用程序崩溃并调用 [ServicesDaemonManager] interruptionHandler。 -[FontServicesDaemonManager 连接]_block_invoke - App crashes with [ServicesDaemonManager] interruptionHandler is called. -[FontServicesDaemonManager connection]_block_invoke
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM