我在散列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的相同属性的路径。
这是因为第1个ReferenceWritableKeyPath的Value为UIColor,而第2个ReferenceWritableKeyPath的Value为Optional<UIColor>
我的项目要求将ReferenceWritableKeyPath存储在字典中,以便关联对象(UILabel)的每个属性只有一个keyPath。由于散列不同,这意味着相同的路径将作为两个不同的关键字存储在字典中。
有没有人知道我有什么办法可以让它正常工作?
~提前道谢
发布于 2021-02-02 04:17:16
正如@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可以是空的),将调用第一个函数。第二个函数在keyPath指向非可选属性时调用。Swift非常聪明,所以我猜它能够找出调用哪个方法,尽管它们几乎有重复的头。
发布于 2021-02-02 03:38:19
使textColorPath也是非可选的,以匹配:
let textColorPath = \UILabel.textColor!或者明确说明类型:
let textColorPath: ReferenceWritableKeyPath<UILabel, UIColor> = \.textColor潜在的问题是\.textColor是一个隐式未包装的可选项,而不是一个“真正的”可选项。在某些上下文中,它被视为底层类型,而在另一些上下文中,它被提升为可选类型。它是一个隐式取消包装的可选项的原因是,将textColor设置为nil是合法的。但您读取的值永远不会为零。
https://stackoverflow.com/questions/65998784
复制相似问题