Reputation: 38025
I have two AnyObject?
variables that I would like to compare for reference equality:
var oldValue: AnyObject?
var newValue: AnyObject?
...
if oldValue != newValue {
changed = true
}
This doesn't work though, as I apparently cannot compare two optionals directly. I want the behavior as if I were comparing id
s in Objective-C, that is:
true
if both are nil
true
if both have a value and the values are also equalfalse
otherwiseIs there an elegant way to write this in Swift (ideally without having to write a custom extension)?
This is the best I've come up with:
if !(oldValue != nil && newValue != nil && oldValue == newValue)
Not very pretty. :(
Upvotes: 20
Views: 14881
Reputation: 11
I believe this is a Swift 5 version of Keith's older solution however this is on generics. If, for example, the thing you are comparing is String?
it will consider that String? = nil
is NOT the same as String? = ""
although both are "empty" at a semantic level
func ==? <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
if let lhs = lhs,
let rhs = rhs {
return lhs == rhs
} else { return lhs == nil && rhs == nil }
}
func ==? <T: AnyObject>(lhs: T?, rhs: T?) -> Bool {
if let lhs = lhs,
let rhs = rhs {
return lhs === rhs
} else { return lhs == nil && rhs == nil }
}
infix operator ==?: ComparisonPrecedence
Upvotes: 1
Reputation: 4663
I liked @Keith's solution. But I think it is not written in Swift 4, as I can not compile it with Swift 4 compiler.
So I have converted his code to Swift 4 version here.
Remember, if you're using higher version of Swift language than Swift 4.1, then this answer is of no need as it provides this feature by default. You can refer here for more details.
Swift 4 version of @Keith's code:
infix operator ==? : ComparisonPrecedence
func ==? <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
if let lhs = lhs, let rhs = rhs {
return lhs == rhs
} else {
return lhs == nil && rhs == nil
}
}
func ==? <T: AnyObject>(lhs: T?, rhs: T?) -> Bool {
if let lhs = lhs, let rhs = rhs {
return lhs === rhs
} else {
return lhs == nil && rhs == nil
}
}
Upvotes: 9
Reputation: 2555
You can overload ==
operator for some Comparable
type
public func ==<T: SomeType>(lhs: T?, rhs: T?) -> Bool {
switch (lhs,rhs) {
case (.some(let lhs), .some(let rhs)):
return lhs == rhs
case (.none, .none):
return true
default:
return false
}
}
Or use ===
comparison for AnyObject
, though, personally I would prefer not to use AnyObject
in the first place.
Upvotes: 0
Reputation: 141
I define a custom infix operator with a function for both reference types and value types.
func ==? <T: Comparable>(lhs: T?, rhs: T?) -> Bool {
if let lhs = lhs, rhs = rhs {
return lhs == rhs
} else{ return lhs == nil && rhs == nil }
}
func ==? <T: AnyObject>(lhs: T?, rhs: T?) -> Bool {
if let lhs = lhs, rhs = rhs {
return lhs === rhs
} else{ return lhs == nil && rhs == nil }
}
infix operator ==? { associativity left precedence 130 }
var aString: String? = nil
var bString: String? = nil
print(aString ==? bString) // true
aString = "test"
bString = "test"
print(aString ==? bString) // true
aString = "test2"
bString = "test"
print(aString ==? bString) // false
aString = "test"
bString = nil
print(aString ==? bString) // false
class TT {}
let x = TT()
var aClass: TT? = TT()
var bClass: TT? = TT()
print(aClass ==? bClass) // false
aClass = TT()
bClass = nil
print(aClass ==? bClass) // false
aClass = nil
bClass = nil
print(aClass ==? bClass) // true
aClass = x
bClass = x
print(aClass ==? bClass) // true
Upvotes: 3
Reputation: 2819
You can use !==
From The Swift Programming Language
Swift also provides two identity operators (
===
and!==
), which you use to test wether two objects references both refer to the same object instance.
Some good examples and explanations are also at Difference between == and ===
On @PEEJWEEJ point, doing the following will result in false
var newValue: AnyObject? = "String"
var oldValue: AnyObject? = "String"
if newValue === oldValue {
print("true")
} else {
print("false")
}
Upvotes: 15
Reputation: 7746
Assuming you're using Comparable entities, this will work on anything:
func optionalsAreEqual<T: Comparable>(firstVal: T?, secondVal: T?) -> Bool{
if let firstVal = firstVal, secondVal = secondVal {
return firstVal == secondVal
}
else{
return firstVal == nil && secondVal == nil
}
}
It's not exactly short and sweet, but it's expressive, clear, and reusable.
Upvotes: 15