Objective c NSObject是可散列的,但采用NSObject的协议不是?
在我提交雷达之前,只需与社区进行一次健康检查: 在.h Obj-C文件中:Objective c NSObject是可散列的,但采用NSObject的协议不是?,objective-c,swift,protocols,hashable,Objective C,Swift,Protocols,Hashable,在我提交雷达之前,只需与社区进行一次健康检查: 在.h Obj-C文件中: @protocol myProto <NSObject> @end 对NSObject类的检查表明,它(或它映射到的NSObjectProtocol)没有实现Hashable协议所需的hashValue方法,也没有明确采用它 因此,尽管如此,在幕后的某个地方,NSObject仍被标记为可哈希的,但并不扩展到采用NSObject/NSObjectProtocol的协议 我有没有窃听器,或者我遗漏了什么 :)
@protocol myProto <NSObject>
@end
对NSObject类的检查表明,它(或它映射到的NSObjectProtocol)没有实现Hashable协议所需的hashValue方法,也没有明确采用它
因此,尽管如此,在幕后的某个地方,NSObject仍被标记为可哈希的,但并不扩展到采用NSObject/NSObjectProtocol的协议
我有没有窃听器,或者我遗漏了什么
:)
张
其他信息:
报告建议:
- 字典的键类型的唯一要求是它是可散列的,并且它实现了
=
- 您确实可以使用协议
NSObjectProtocol
不继承自Hashable
。这是这里的关键问题
它实际上不能从Hashable
继承,因为Hashable
需要一个名为hashValue
的方法,而NSObjectProtocol
需要一个名为hash
的方法
另一方面,NSObject
类可以实现NSObjectProtocol
和Hashable
同样的问题也发生在equalable
上
编辑:
还有一个更微妙的问题。您不能在需要equalable
的地方使用协议,您始终需要使用采用equalable
的类类型或值类型。原因是一个键采用相等是不够的,字典中的所有键都必须彼此相等
例如,如果您有一个类a
和一个类B
,这两个类都符合equalable
,然后可以将A
的实例与A
的其他实例进行比较,也可以将B
的实例与B
的其他实例进行比较,但不能将A
的实例与B
的实例进行比较。这就是为什么不能将A
的实例和B
的实例用作同一词典中的键
请注意,每个NSObject
都可以与任何其他NSObject
相等,因此NSObject
是字典中允许的键类型。我同意这似乎是缺少的功能。对于任何感兴趣的人,我做了一个小包装来处理它
struct HashableNSObject<T: NSObjectProtocol>: Hashable {
let value: T
init(_ value: T) {
self.value = value
}
static func == (lhs: HashableNSObject<T>, rhs: HashableNSObject<T>) -> Bool {
return lhs.value.isEqual(rhs.value)
}
func hash(into hasher: inout Hasher) {
hasher.combine(value.hash)
}
}
或者,您可以使用NSObjectProtocol.hash作为密钥
var dictTwo: [Int:Int]?
dictTwo[myProtoInstance.hash] = 0
谢谢你的评论。我确实看到(正如我在问题中提到的)NSObjectProtocol没有实现所需的哈希方法,但我没有遵循“更微妙的问题”的论点;Equalable部分只是比较散列,不关心A和B是什么,只要它们采用协议。我看到的问题是桥接无法将Swift的HashablehashValue
和Equalable==
映射到Objective-C NSObject协议的isEqual:
和hash
@TeoSartori it's不可能用那种方式把它们连接起来Obj-C
无法表示==
运算符,您不能将一个方法名桥接到另一个方法名。一个对象可以实现两者,但你不能仅仅使它们相等,这将是一个危险的先例。无论如何,即使是纯Swift协议,也不能对字典键使用协议类型。对象的哈希值不是唯一值。您可以简单地将其用作字典中的键。
let foo = [MyObjectProtocol]()
let bar = Set<HashableNSObject<MyObjectProtocol>>()
fun1(foo.map { HashableNSObject($0) })
fun2(bar.map { $0.value })
var dictTwo: [Int:Int]?
dictTwo[myProtoInstance.hash] = 0