Swift 2.0 设置在包含 NSObject 子类时无法按预期工作
Swift 2.0 Set not working as expected when containing NSObject subclass
将我们的代码库升级到 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
看起来新的 Set 没有使用 hashValue 进行内部操作。任何想法是一个错误,还是解决此问题的方法?
我试了一下你的代码。我能够通过不再子类化 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
}
}
//: 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
我花了很多时间寻找这个问题的正确答案,直到我找到这个 Question/Answer。我已经在 XCode Playground 中回到基础知识,看看发生了什么。在 Swift Set
中使用 NSObject
的子类使代码更具可读性。
将我们的代码库升级到 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
看起来新的 Set 没有使用 hashValue 进行内部操作。任何想法是一个错误,还是解决此问题的方法?
我试了一下你的代码。我能够通过不再子类化 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
}
}
//: 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
我花了很多时间寻找这个问题的正确答案,直到我找到这个 Question/Answer。我已经在 XCode Playground 中回到基础知识,看看发生了什么。在 Swift Set
中使用 NSObject
的子类使代码更具可读性。