Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Objective c NSObject是可散列的,但采用NSObject的协议不是?_Objective C_Swift_Protocols_Hashable - Fatal编程技术网

Objective c NSObject是可散列的,但采用NSObject的协议不是?

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的协议 我有没有窃听器,或者我遗漏了什么 :)

在我提交雷达之前,只需与社区进行一次健康检查:

在.h Obj-C文件中:

@protocol myProto <NSObject> 
@end
对NSObject类的检查表明,它(或它映射到的NSObjectProtocol)没有实现Hashable协议所需的hashValue方法,也没有明确采用它

因此,尽管如此,在幕后的某个地方,NSObject仍被标记为可哈希的,但并不扩展到采用NSObject/NSObjectProtocol的协议

我有没有窃听器,或者我遗漏了什么

:) 张

其他信息:

报告建议:

  • 字典的键类型的唯一要求是它是可散列的,并且它实现了
    =
  • 您确实可以使用协议
字典键类型的哈希值 类型必须是可散列的,才能用作字典的键类型,也就是说,该类型必须提供一种为自身计算散列值的方法。哈希值是一个Int值,对于比较相等的所有对象都是相同的,因此,如果A==b,则紧随其后的是A.hashValue==b.hashValue

Swift的所有基本类型(如String、Int、Double和Bool)在默认情况下都是可散列的,并且所有这些类型都可以用作字典的键。默认情况下,没有关联值的枚举成员值(如枚举中所述)也可以散列

注 您可以使用自己的自定义类型作为字典密钥类型,方法是使它们符合Swift标准库中的哈希协议。符合Hashable协议的类型必须提供名为hashValue的gettable Int属性,并且还必须提供“is equal”运算符(=)的实现。类型的hashValue属性返回的值在同一程序的不同执行中或在不同程序中不必相同。 有关遵守协议的更多信息,请参阅协议


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的Hashable
hashValue
和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