jjaeko
jjaeko

Reputation: 235

how to compare value in swift optional

var someString: String? = "a"    
someString = "b" 
// or someString = nil

Condition: someString is not nil and "a"

Example:

if someString != nil && someString != "a" {

}

Is it possible to condition a single?

Upvotes: 5

Views: 14408

Answers (8)

Arbitur
Arbitur

Reputation: 39081

This extension of Optional will compare Optionals and its wrapped value.

extension Optional: Comparable where Wrapped: Comparable {

    // Optional <=> Optional

    public static func < (lhs: Optional<Wrapped>, rhs: Optional<Wrapped>) -> Bool {
        switch lhs {
        case .some(let v): return v < rhs
        case .none: return false
        }
    }

    public static func <= (lhs: Optional<Wrapped>, rhs: Optional<Wrapped>) -> Bool {
        switch lhs {
        case .some(let v): return v <= rhs
        case .none: return false
        }
    }

    public static func >= (lhs: Optional<Wrapped>, rhs: Optional<Wrapped>) -> Bool {
        switch lhs {
        case .some(let v): return v >= rhs
        case .none: return false
        }
    }

    public static func > (lhs: Optional<Wrapped>, rhs: Optional<Wrapped>) -> Bool {
        switch lhs {
        case .some(let v): return v > rhs
        case .none: return false
        }
    }


    // Optional <=> Wrapped

    public static func < (lhs: Optional<Wrapped>, rhs: Wrapped) -> Bool {
        switch lhs {
        case .some(let v): return v < rhs
        case .none: return false
        }
    }

    public static func <= (lhs: Optional<Wrapped>, rhs: Wrapped) -> Bool {
        switch lhs {
        case .some(let v): return v <= rhs
        case .none: return false
        }
    }

    public static func >= (lhs: Optional<Wrapped>, rhs: Wrapped) -> Bool {
        switch lhs {
        case .some(let v): return v >= rhs
        case .none: return false
        }
    }

    public static func > (lhs: Optional<Wrapped>, rhs: Wrapped) -> Bool {
        switch lhs {
        case .some(let v): return v > rhs
        case .none: return false
        }
    }


    // Wrapped <=> Optional

    public static func < (lhs: Wrapped, rhs: Optional<Wrapped>) -> Bool {
        switch rhs {
        case .some(let v): return lhs < v
        case .none: return false
        }
    }

    public static func <= (lhs: Wrapped, rhs: Optional<Wrapped>) -> Bool {
        switch rhs {
        case .some(let v): return lhs <= v
        case .none: return false
        }
    }

    public static func >= (lhs: Wrapped, rhs: Optional<Wrapped>) -> Bool {
        switch rhs {
        case .some(let v): return lhs >= v
        case .none: return false
        }
    }

    public static func > (lhs: Wrapped, rhs: Optional<Wrapped>) -> Bool {
        switch rhs {
        case .some(let v): return lhs > v
        case .none: return false
        }
    }
}

Upvotes: 0

lkraider
lkraider

Reputation: 4180

The correct way in Swift 3 is to use a multi-clause condition:

if let bString = someString, bString != "a" {
    print("bString: '\(bString)' is not nil and is different from 'a'")
}

https://github.com/apple/swift-evolution/blob/master/proposals/0099-conditionclauses.md

Upvotes: 7

John LaBarge
John LaBarge

Reputation: 158

One trick:

func existsAnd<T: Equatable>(x:T?, _ it:T ) -> Bool {
    return x.flatMap { $0 == it } ?? false
}

var str : String? = "hello"
existsAnd(str, "hello")
str = nil
existsAnd(str, "hello")

Upvotes: 1

ZLN
ZLN

Reputation: 41

Have a try with a where clause:

if let forcedString = someString where forcedString != "a" {
    print("Yea")
} else {
    print("Err")
}

Upvotes: 4

john07
john07

Reputation: 560

swift 1.2 for var a:int?; var b:int? has matrix

nil == nil; // true
nil > nil;  // false
nil > 2;    // false
2 > nil;    // true
2 > 1;      // true

Upvotes: 1

Marc Nunes
Marc Nunes

Reputation: 238

a bit late to the party but how about just this (assuming you do want to compare strings):

if someName.compare(displayName) == .OrderedSame{
  //true
}

Upvotes: 0

Antonio
Antonio

Reputation: 72760

I presume you mean that you would like to test for someString != nil and someString != "a" in a single logical expression (and not two in and).

No, I don't think that's possible using the built in operators, but doable implementing a String extension like this:

extension String {
    func isDifferentThan(value: String?) -> Bool {
        return value != nil && self != value?
    }
}

and you can use as follows:

someString = nil
"a".isDifferentThan(someString) // Return false

someString = "b"
"a".isDifferentThan(someString) // Return true

someString = "a"
"a".isDifferentThan(someString) // Return false

Addendum: A more elegant solution is to define your own logical operator. I have used !~= but feel free to use your own.

infix operator !~= { associativity left }
func !~= (a: String?, b: String?) -> Bool {
    if a == nil || b == nil {
        return false
    }

    return a != b
}

Tested as follows:

someString = nil
someString !~= "a" // Returns false

someString = "b"
someString !~= "a" // Returns true

someString = "a"
someString !~= "a" // Returns false

someString = nil
someString !~= nil // Returns false

You can fine tune it when dealing with nil values (such as add a check for both having nil and returning true, in case you want the condition "both sides are nil" to evaluate to true)

Upvotes: 3

David Berry
David Berry

Reputation: 41226

You can collapse the whole thing using the optional unwrapping operator:

if someString? == "a" {

Upvotes: 0

Related Questions