在Swift中在同一类中实现Hashable和NSCoding
在同一Swift类(或结构)中采用哈希和NSCoding协议时,我遇到了一个问题。哈希性和编码/解码都是独立工作的。但是,一旦NSCoder恢复了对象,哈希性就会丢失 首先,我必须使它成为一个类而不是一个结构,因为显然NSCoding不能与结构一起工作。因此,我显然需要从NSObject继承(它也恰好是可散列的)。不幸的是,NSObject的这种内置哈希性似乎阻止了我以我想要的方式(我想)使自己的类成为可哈希的 这是我的班级:在Swift中在同一类中实现Hashable和NSCoding,swift,nscoding,nscoder,hashable,Swift,Nscoding,Nscoder,Hashable,在同一Swift类(或结构)中采用哈希和NSCoding协议时,我遇到了一个问题。哈希性和编码/解码都是独立工作的。但是,一旦NSCoder恢复了对象,哈希性就会丢失 首先,我必须使它成为一个类而不是一个结构,因为显然NSCoding不能与结构一起工作。因此,我显然需要从NSObject继承(它也恰好是可散列的)。不幸的是,NSObject的这种内置哈希性似乎阻止了我以我想要的方式(我想)使自己的类成为可哈希的 这是我的班级: class TileMapCoords : NSObject, NS
class TileMapCoords : NSObject, NSCoding {
var row: Int
var column: Int
init(row: Int, column: Int) {
self.row = row
self.column = column
}
// Hashable
override var hashValue: Int {
return column*numTMRows + row
}
static func == (lhs: TileMapCoords, rhs: TileMapCoords) -> Bool {
return
lhs.row == rhs.row &&
lhs.column == rhs.column
}
// do I even need this?
override func isEqual(_ object: Any?) -> Bool {
if let otherCoords = object as? TileMapCoords {
return self == otherCoords
} else {
return false
}
}
// NSCoding
required init?(coder aDecoder: NSCoder) {
row = aDecoder.decodeInteger(forKey: "TileMapCoords.row")
column = aDecoder.decodeInteger(forKey: "TileMapCoords.column")
}
func encode(with aCoder: NSCoder) {
aCoder.encode(row, forKey: "TileMapCoords.row")
aCoder.encode(column, forKey: "TileMapCoords.column")
}
}
我正在创建一组这些对象,并对它们进行编码/解码,如下所示:
编码:
aCoder.encode(itemsCollected, forKey: "GameData.itemsCollected")
解码:
var itemsCollected = Set<TileMapCoords>()
itemsCollected = aDecoder.decodeObject(forKey: "GameData.itemsCollected") as! Set<TileMapCoords>
如果我创建了一个TileMapCoords对象,该对象的行和列与itemsCollected集中的对象相同,“contains”方法会告诉我
1) 最初是在集合中
2) 一旦集合被NSCoder还原/解码,则不在集合中
奇怪的是,对象在集合中,我已经验证了我的对象和集合中的对象具有相同的散列值,并且根据==运算符和isEqual方法是相等的
我需要帮助解决这个问题,或者考虑另一种方法在同一个类中同时具有hashability和NSCodability(可能不重写NSObject?要自定义
NSObject
子类中的哈希和相等性,需要重写hash
属性和isEqual(:)
方法
不幸的是,Swift onlyNSObject.hashValue
属性是可重写的(从Swift 4.1开始),但您决不能重写它。
重写<代码>散列< /代码>,以便基金会拾取正确的散列行为——否则基础将使用从“代码”> NSObjult>代码继承的实现,这是基于对象标识的。这不适用于具有自定义isEqual(:)
实现的TileMapCoords
通过
NSCoding
解码的集合首先创建为NSSet
实例,然后桥接到Swift的Set
类型<代码> NSSET 是一个基础类,因此它使用Foundation的哈希API——很不幸的是,因为上面的代码> TrimaPoCORDS ,导致了您注意到的奇怪行为。将hashValue
替换为hash
将解决此问题。您能解释一下为什么需要实现NSCoding吗?Codable的全部意义在于,它使对结构进行编码变得容易,并且在任何情况下,如果不能使用Codable,您都不会使用NSCoding。那么为什么不直接使用Codable呢?你的代码对我来说很好,不需要在解码后构建第二个集合。请用一个完全可复制的例子来演示你的问题,更新你的问题。在我对集合进行编码然后解码之前,代码工作正常。然后“contains”方法似乎不再在集合中找到(相同的)对象。如果我能将它与结构一起使用,那就太完美了。我将尝试实现它。正如我所说的,你的代码对我有用。甚至在编码和解码之后。这就是为什么您需要发布一个完整的示例来演示这个问题。张贴一些可以复制粘贴到操场上的东西。
let itemsCollectedCopy = aDecoder.decodeObject(forKey: "GameData.itemsCollected") as! Set<TileMapCoords>
var itemsCollected = Set<TileMapCoords>()
for coords in itemsCollectedCopy {
itemsCollected.insert(coords) }
if curGameData!.itemsCollected.contains(location) {
// do something
}