compare two NSObject in Swift
NSObject
has a method named isEqual(object:)
that is used for comparing different objects. The default implementation just compares instance pointers, but subclasses can override this method to do custom comparisons.
For example:
class Foo : NSObject {
var number = 0
override func isEqual(object: AnyObject?) -> Bool {
if let otherFoo = object as? Foo {
return self.number == otherFoo.number
}
return false
}
}
Swift's ==
operatior automatically uses the isEqual(object:)
method when comparing NSObject instances.
let foo1 = Foo()
let foo2 = Foo()
print("Equal: \(foo1 == foo2)") // true
foo1.number = 1
foo2.number = 2
print("Equal: \(foo1 == foo2)") // false
let anotherObject = NSObject()
print("Equal: \(foo1 == anotherObject)") // false
How to override NSObject's default comparison in Swift
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
How to compare Any value types
The only way to do this is with a function other than ==
that takes a type parameter, and then compares the values if they are both of that type:
func isEqual<T: Equatable>(type: T.Type, a: Any, b: Any) -> Bool {
guard let a = a as? T, let b = b as? T else { return false }
return a == b
}
Now, using your variables above, you can compare them like this:
var any1: Any = 1
var any2: Any = 1
var any3: Any = "test"
var any4: Any = "test"
isEqual(type: Int.self, a: any1, b: any2) // true
isEqual(type: Int.self, a: any2, b: any3) // false
isEqual(type: String.self, a: any3, b: any4) // true
Compare two objects in Swift
You want Comparable, not Equatable. Equatable only has ==
.
Related Topics
Dynamictype of Optional Chaining Not The Same as Assignment
Siblings Relationship Between Same Models in Vapor
How to Get a Class with Generic Type Accept an Array of Different by Same Generic Types
Audiounit Callback and Synchronization: How to Ensure Thread Safety with Gcd
How to Avoid Parent Scrollview to Clip Internal Scrollview
Swift Combine: Turn a Publisher into a Read-Only Currentvaluesubject
Add New Card Is Not Being Called in Stripe Paymentoptionviewcontroller
Working with Nested Async Firebase Calls Swiftui
Realitykit - Add Force to Entity at Specific Point
Get Url from Open Dialog of Standard Swift Document-Based Application
Error When Running Coreml in The Background: Error Computing Nn Outputs Error
Tableview to Display Different Images on New Controller
How to Access Switch Results of a Case
How to Convert String to Date Without Time in Swift 3
Implementing Undo and Redo in a UItextview with Attributedtext
Scenekit Ar Game Fps Getting Low and The Device Getting Hot with Use