简体   繁体   English

将 KeyPaths 存储在 Dictionary/HashMap 中

[英]Storing KeyPaths in Dictionary/HashMap

I'm facing a problem when hashing a ReferenceWritableKeyPath .哈希ReferenceWritableKeyPath时遇到问题。 It appears that the hash function also takes the generic properties of the ReferenceWritableKeyPath into account when hashing the key path.似乎 hash function 在散列密钥路径时也考虑了ReferenceWritableKeyPath的通用属性。 I've included sample code to show why this is a problem:我已经包含示例代码来说明为什么这是一个问题:

struct TestStruct<T> {
    // This function should only be callable if the value type of the path reference == T
    func doSomething<Root>(object: Root, path: ReferenceWritableKeyPath<Root, T>) -> Int {
        // Do something
        print("Non-optional path:   \(path)                    \(path.hashValue)")
        return path.hashValue
    }
}

let label = UILabel()
let textColorPath = \UILabel.textColor

let testStruct = TestStruct<UIColor>()
let hash1 = testStruct.doSomething(object: label, path: \.textColor)
let hash2 = textColorPath.hashValue
print("Optional path:       \(textColorPath)    \(hash2)")

If you run the code above, you will notice that hash1 and hash2 are different despite being paths to the same property of the UILabel.如果你运行上面的代码,你会注意到 hash1 和 hash2 是不同的,尽管它们是指向 UILabel 相同属性的路径。

This happens because the 1st ReferenceWritableKeyPath has a Value that is UIColor while the 2nd ReferenceWritableKeyPath has a Value that is Optional<UIColor>发生这种情况是因为第一个ReferenceWritableKeyPathValueUIColor ,而第二个ReferenceWritableKeyPathValueOptional<UIColor>

My project requires the ReferenceWritableKeyPath s to be stored in a dictionary so that there is only one keyPath for each property of the associated object (UILabel).我的项目需要将ReferenceWritableKeyPath存储在字典中,以便关联的 object (UILabel) 的每个属性只有一个 keyPath。 Since the hashes are different, this means that the same path will be stored as 2 different keys in the dictionary.由于哈希值不同,这意味着相同的路径将在字典中存储为 2 个不同的键。

Does anyone know of a way that I can get this to work?有谁知道我可以让它工作的方法?

~Thanks in advance ~提前谢谢

Make textColorPath also be non-optional, to match:使textColorPath也不是可选的,以匹配:

let textColorPath = \UILabel.textColor!

or be explicit about the type:或明确说明类型:

let textColorPath: ReferenceWritableKeyPath<UILabel, UIColor> = \.textColor

The underlying problem is that \.textColor is an implicitly unwrapped optional rather than a "real" optional.潜在的问题是\.textColor是一个隐式展开的可选而不是“真正的”可选。 In some contexts that gets treated as the underlying type, and in others it's promoted to an Optional.在某些情况下,它被视为基础类型,而在其他情况下,它被提升为 Optional。 The reason it's an implicitly unwrapped optional is because it is legal to set textColor to nil.它是隐式展开的可选项的原因是因为将textColor设置为 nil 是合法的。 But the value you read will never be nil.但是您读取的值永远不会为零。

As @Rob Napier pointed out, the problem was with the generic types themselves.正如@Rob Napier 指出的那样,问题出在泛型类型本身。 The way I fixed the problem was by splitting the doSomething into two separate methods:我解决问题的方法是将doSomething拆分为两个单独的方法:

func doSomething<Root>(object: Root, path: ReferenceWritableKeyPath<Root, T?>) -> Int {
    // Do something
    print("Non-optional path:   \(path)                    \(path.hashValue)")
    return path.hashValue
}

func doSomething<Root>(object: Root, path: ReferenceWritableKeyPath<Root, T>) -> Int {
    // Do something
    print("Non-optional path:   \(path)                    \(path.hashValue)")
    return path.hashValue
}

The 1st one will get called when T is an optional type such as in the example above (where UIColor can be nil).第一个将在T是可选类型时调用,例如上面的示例(其中UIColor可以为 nil)。 The 2nd one gets called when the keyPath points to a non-optional property.当 keyPath 指向非可选属性时,第二个被调用。 Swift is pretty smart so I guess it's able to figure out which metthod to call despite them having almost duplicate headers. Swift 非常聪明,所以我想它能够找出调用哪个方法,尽管它们几乎有重复的标题。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM