包含 NSObject 子类时,Swift 2.0 Set 无法按预期工作
Posted
技术标签:
【中文标题】包含 NSObject 子类时,Swift 2.0 Set 无法按预期工作【英文标题】:Swift 2.0 Set not working as expected when containing NSObject subclass 【发布时间】:2015-09-22 20:42:49 【问题描述】:将我们的代码库升级到 Swift2 后,我遇到了不寻常的问题。 Set 没有按预期进行减法或联合。
class A: NSObject
let h: Int
init(h: Int)
self.h = h
override var hashValue: Int
return h
func ==(lhs: A, rhs: A) -> Bool
return lhs.hashValue == rhs.hashValue
let a = A(h: 1)
let b = A(h: 1)
var sa = Set([a])
let sb = Set([b])
sa.subtract(sb).count // Swift1.2 prints 0, Swift 2 prints 1
sa.contains(a) // Swift1.2 true, Swift 2 true
sa.contains(b) // Swift1.2 true, Swift 2 false
看起来 new Set 没有使用 hashValue 进行内部操作。知道这是一个错误,还是解决此问题的方法?
【问题讨论】:
【参考方案1】:我玩了一下你的代码。我能够通过不再继承 NSObject 的子类,而是遵循 Hashable 协议来让它工作:
class A: Hashable
let h: Int
init(h: Int)
self.h = h
var hashValue: Int
return h
func ==(lhs: A, rhs: A) -> Bool
return lhs.hashValue == rhs.hashValue
let a = A(h: 1)
let b = A(h: 1)
var sa = Set([a])
let sb = Set([b])
sa.subtract(sb).count // Swift1.2 prints 0, Swift 2 prints 1
sa.contains(a) // Swift1.2 true, Swift 2 true
sa.contains(b) // Swift1.2 true, Swift 2 false
a.hashValue == b.hashValue
当您从 NSObject 继承时,您的 ==
重载实际上并没有被执行。如果您希望它与 NSObject 一起使用,则必须覆盖 isEquals:
override func isEqual(object: AnyObject?) -> Bool
if let object = object as? A
return object.h == self.h
else
return false
【讨论】:
谢谢!我遇到了 MKAnnotation 子类(也需要扩展 NSObject)的问题。你有关于这个主题的一些文档的链接吗? 似乎需要 isEqual 和 hashValue 才能在 Swift 3 中正确使用 NSObject 进行 Set 【参考方案2】://: Playground - noun: a place where people can play
import Foundation
class X: NSObject
var x:String
var y:Int
init(x:String, y:Int)
self.x = x
self.y = y
super.init()
override var hashValue: Int
return x.hashValue ^ y.hashValue
override func isEqual(object: AnyObject?) -> Bool
if let rhs = object as? X
return x == rhs.x && y == rhs.y
else
return false
func == (lhs:X, rhs:X) -> Bool
return lhs.isEqual(rhs)
let x = X(x: "x1", y: 1)
let y = X(x: "x1", y: 1)
X(x: "x1", y: 1) == X(x: "x1", y: 1) // Swift 'x == y' (true)
x.isEqual(y) // Obj-C '[x isEqual: y]' (true)
var s:Set<X> = [X(x: "x1", y: 1)]
s.count // count == 1
s.insert(X(x: "x2", y: 1))
s.count // count == 2
s.insert(X(x: "x1", y: 1))
s.count // count == 2
s.insert(X(x: "x2", y: 1))
s.count // count == 2
我花时间寻找这个问题的正确答案,直到我遇到这个问题/答案。我已经恢复到 XCode Playground 中的基础知识,看看发生了什么。在 Swift 中使用 NSObject
的子类 Set
会产生一堆更具可读性的代码。
【讨论】:
我不知道为什么这么多人选择了其他答案。对我来说,这个是有价值和正确的。非常感谢。 顺便提一下,在NSObjectProtocol
中是必需的,如果你覆盖func isEqual(_ object: Any?) -> Bool
,你也必须覆盖var hash: Int get
。就像在文档中一样,它说If two objects are equal (as determined by the isEqual(_:) method), they must have the same hash value.
。 developer.apple.com/reference/objectivec/nsobjectprotocol/…以上是关于包含 NSObject 子类时,Swift 2.0 Set 无法按预期工作的主要内容,如果未能解决你的问题,请参考以下文章
在 NSObject 的子类上实现啥方法以允许在 swift 操场上进行漂亮的打印?
Swift 2.0 OneSignal .pushNotification