如何在 Swift 中覆盖 NSObject 的默认比较
How to override NSObject's default comparison in Swift
我有一个符合 NSObject, NSCoding
的自定义 class Player
。 Player
对象用 id: String!
实例化
我遇到的一个问题是当我执行如下操作时:
let listOfPlayers = [Player]()
//populate listOfPlayers
if listOfPlayers.contains(aPlayer) ...
具体来说,contains
将 return 结果基于内存指针,而不是基于 id
值。因此,在某些情况下我会得到 true
,而在其他情况下我会得到 false
。
我想覆盖默认比较方法,并执行了以下操作:
func isEqual(object: AnyObject?) -> Bool {
if let otherPlayer = object as? Player {
return self.id == otherPlayer.id
}
return false
}
static func == (lhs: Player, rhs: Player) -> Bool {
return lhs.id == rhs.id
}
但是,这些函数没有被执行。我也尝试添加 override
,但它 return 是一个错误“方法没有覆盖其 superclass 中的任何方法`
让客户比较器仅比较 id
元素的正确方法是什么?
谢谢!
我把下面的代码扔到了操场上。
class Player : NSObject {
var id : String = ""
static func == (lhs: Player, rhs: Player) -> Bool {
print("We checked here")
return lhs.id == rhs.id
}
}
//Direct comparison will call our function.
if Player() == Player() {
print("yay")
}
let players : [Player] = [Player()]
//Even though Player() has same id, it is new object in memory so this won't evaluate as true when comparing with `contains()`,
//hence why "we checked here" isn't called again.
if players.contains(Player()) {
print("Dang we suck")
}
//Could check with something like this if you want to check your array for a particular id.
if players.contains(where: {[=10=].id == Player().id }) {
print("Im awesome")
}
输出:
We checked here
yay
Im awesome
我相信 [NSObject].contains()
使用三重相等的比较 ===
而不是直接相等比较,后者将检查它是否是内存中的同一对象,而不是特定的 id
.如您所见, We checked here
仅在直接比较时调用。您可以使用 contains(where: predicate)
方法来获取特定条件。
从 Swift 3 开始,NSObject
的 isEqual
方法采用 Any?
参数,所以你没有覆盖正确的方法,那就是
为什么它从未被调用。
你还应该覆盖 var hash: Int
(相等的对象 必须 具有相同的散列)——否则该对象在可散列集合(集合、字典)中的行为会错误:
class Player: NSObject {
let id: String
init(id: String) { self.id = id }
override func isEqual(_ object: Any?) -> Bool {
if let other = object as? Player {
return self.id == other.id
} else {
return false
}
}
override var hash: Int {
return id.hashValue
}
}
一些测试:
let p1 = Player(id: "a")
let p2 = Player(id: "a")
print(p1 == p2) // true
print(p1 != p2) // false
// Native Swift set:
let set = Set([Player(id: "x"), Player(id: "y"), Player(id: "z")])
print(set.contains(Player(id: "y"))) // true
// Foundation set:
let nsset = NSSet(objects: Player(id: "x"), Player(id: "y"), Player(id: "z"))
print(nsset.contains(Player(id: "y"))) // true
我有一个符合 NSObject, NSCoding
的自定义 class Player
。 Player
对象用 id: String!
我遇到的一个问题是当我执行如下操作时:
let listOfPlayers = [Player]()
//populate listOfPlayers
if listOfPlayers.contains(aPlayer) ...
具体来说,contains
将 return 结果基于内存指针,而不是基于 id
值。因此,在某些情况下我会得到 true
,而在其他情况下我会得到 false
。
我想覆盖默认比较方法,并执行了以下操作:
func isEqual(object: AnyObject?) -> Bool {
if let otherPlayer = object as? Player {
return self.id == otherPlayer.id
}
return false
}
static func == (lhs: Player, rhs: Player) -> Bool {
return lhs.id == rhs.id
}
但是,这些函数没有被执行。我也尝试添加 override
,但它 return 是一个错误“方法没有覆盖其 superclass 中的任何方法`
让客户比较器仅比较 id
元素的正确方法是什么?
谢谢!
我把下面的代码扔到了操场上。
class Player : NSObject {
var id : String = ""
static func == (lhs: Player, rhs: Player) -> Bool {
print("We checked here")
return lhs.id == rhs.id
}
}
//Direct comparison will call our function.
if Player() == Player() {
print("yay")
}
let players : [Player] = [Player()]
//Even though Player() has same id, it is new object in memory so this won't evaluate as true when comparing with `contains()`,
//hence why "we checked here" isn't called again.
if players.contains(Player()) {
print("Dang we suck")
}
//Could check with something like this if you want to check your array for a particular id.
if players.contains(where: {[=10=].id == Player().id }) {
print("Im awesome")
}
输出:
We checked here
yay
Im awesome
我相信 [NSObject].contains()
使用三重相等的比较 ===
而不是直接相等比较,后者将检查它是否是内存中的同一对象,而不是特定的 id
.如您所见, We checked here
仅在直接比较时调用。您可以使用 contains(where: predicate)
方法来获取特定条件。
从 Swift 3 开始,NSObject
的 isEqual
方法采用 Any?
参数,所以你没有覆盖正确的方法,那就是
为什么它从未被调用。
你还应该覆盖 var hash: Int
(相等的对象 必须 具有相同的散列)——否则该对象在可散列集合(集合、字典)中的行为会错误:
class Player: NSObject {
let id: String
init(id: String) { self.id = id }
override func isEqual(_ object: Any?) -> Bool {
if let other = object as? Player {
return self.id == other.id
} else {
return false
}
}
override var hash: Int {
return id.hashValue
}
}
一些测试:
let p1 = Player(id: "a")
let p2 = Player(id: "a")
print(p1 == p2) // true
print(p1 != p2) // false
// Native Swift set:
let set = Set([Player(id: "x"), Player(id: "y"), Player(id: "z")])
print(set.contains(Player(id: "y"))) // true
// Foundation set:
let nsset = NSSet(objects: Player(id: "x"), Player(id: "y"), Player(id: "z"))
print(nsset.contains(Player(id: "y"))) // true