2

我在散列一个ReferenceWritableKeyPath. 散列函数似乎ReferenceWritableKeyPath在散列密钥路径时也考虑了 的通用属性。我已经包含示例代码来说明为什么这是一个问题:

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)")

如果你运行上面的代码,你会注意到 hash1 和 hash2 是不同的,尽管它们是指向 UILabel 相同属性的路径。

发生这种情况是因为第一个ReferenceWritableKeyPath有一个Valuethat isUIColor而第二个ReferenceWritableKeyPath有一个Valuethat isOptional<UIColor>

我的项目要求将ReferenceWritableKeyPaths 存储在字典中,以便关联对象 (UILabel) 的每个属性只有一个 keyPath。由于哈希值不同,这意味着相同的路径将在字典中存储为 2 个不同的键。

有谁知道我可以让它工作的方法?

~提前谢谢

4

2 回答 2

1

MaketextColorPath也是非可选的,以匹配:

let textColorPath = \UILabel.textColor!

或明确说明类型:

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

潜在的问题是这\.textColor是一个隐式展开的可选而不是“真正的”可选。在某些情况下,它被视为基础类型,而在其他情况下,它被提升为 Optional。它是隐式展开的可选项的原因是设置textColor为 nil 是合法的。但是您读取的值永远不会为零。

于 2021-02-01T19:38:18.600 回答
0

正如@Rob Napier 指出的那样,问题出在泛型类型本身。我解决问题的方法是将其拆分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
}

T是可选类型时,第一个将被调用,例如上面的示例(其中UIColor可以是 nil)。当 keyPath 指向非可选属性时,第二个被调用。Swift 非常聪明,所以我想它能够找出调用哪个方法,尽管它们几乎有重复的标题。

于 2021-02-01T20:17:16.310 回答