I have a custom class Player
that conforms to NSObject, NSCoding
. A Player
object is instantiated with a id: String!
One of the issues I am encountering is when I perform an operation like the following:
let listOfPlayers = [Player]()
//populate listOfPlayers
if listOfPlayers.contains(aPlayer) ...
Specifically, the contains
would return results based on the memory pointer, and not based on the id
value. As such, I would get a true
in some cases and false
in others.
I would like to override the default comparison methods, and did the following:
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
}
However, these functions are not being executed. I have also tried to add override
, but it returns an error "Method does not override any method from its superclass`
What is the right way to have a customer comparator so it is only comparing the id
element?
Thanks!
As of Swift 3, the isEqual
method of NSObject
takes an Any?
parameter, so you are not overriding the correct method, that's
why it is never called.
You should also override var hash: Int
(equal objects must have the same hash) – otherwise the object will behave wrongly in hashable collections (sets, dictionaries):
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
}
}
Some tests:
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