Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Most elegant way to compare two optionals in Swift

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 ids in Objective-C, that is:

  • true if both are nil
  • true if both have a value and the values are also equal
  • false otherwise

Is 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. :(

like image 757
devios1 Avatar asked Mar 17 '16 16:03

devios1


People also ask

What's the difference between == and === Swift?

The difference between == and === in Swift is: == checks if two values are equal. === checks if two objects refer to the same object.

When should you use optionals Swift?

Optional types or Optionals in Swift You use optionals in situations where a value may be absent. An optional represents two possibilities: Either there is a value, and you can unwrap the optional to access that value, or there isn't a value at all.

What is an optional in Swift and what problem do optionals solve?

Optionals are a fundamental part of swift coding. Keeping it simple, we can say that optionals help us to separate good code from bad code and hence prevent crashes. Different programming languages uses different preventive measures to avoid a crash. But most of them are helpless in most of the cases.

What are the optionals in Swift?

Optionals say either "there is a value, and it equals x" or "there isn't a value at all". An Optional is a type on its own, actually one of Swift 4's new super-powered enums. It has two possible values, None and Some(T), where T is an associated value of the correct data type available in Swift 4.


3 Answers

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.

like image 65
GetSwifty Avatar answered Sep 22 '22 00:09

GetSwifty


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")
}
like image 37
sbarow Avatar answered Sep 23 '22 00:09

sbarow


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
    }
}
like image 38
Nitesh Borad Avatar answered Sep 21 '22 00:09

Nitesh Borad