Swift: Testing optionals for nil

205,391

Solution 1

In Xcode Beta 5, they no longer let you do:

var xyz : NSString?

if xyz {
  // Do something using `xyz`.
}

This produces an error:

does not conform to protocol 'BooleanType.Protocol'

You have to use one of these forms:

if xyz != nil {
   // Do something using `xyz`.
}

if let xy = xyz {
   // Do something using `xy`.
}

Solution 2

To add to the other answers, instead of assigning to a differently named variable inside of an if condition:

var a: Int? = 5

if let b = a {
   // do something
}

you can reuse the same variable name like this:

var a: Int? = 5

if let a = a {
    // do something
}

This might help you avoid running out of creative variable names...

This takes advantage of variable shadowing that is supported in Swift.

Solution 3

Swift 3.0, 4.0

There are mainly two ways of checking optional for nil. Here are examples with comparison between them

1. if let

if let is the most basic way to check optional for nil. Other conditions can be appended to this nil check, separated by comma. The variable must not be nil to move for the next condition. If only nil check is required, remove extra conditions in the following code.

Other than that, if x is not nil, the if closure will be executed and x_val will be available inside. Otherwise the else closure is triggered.

if let x_val = x, x_val > 5 {
    //x_val available on this scope
} else {

}

2. guard let

guard let can do similar things. It's main purpose is to make it logically more reasonable. It's like saying Make sure the variable is not nil, otherwise stop the function. guard let can also do extra condition checking as if let.

The differences are that the unwrapped value will be available on same scope as guard let, as shown in the comment below. This also leads to the point that in else closure, the program has to exit the current scope, by return, break, etc.

guard let x_val = x, x_val > 5 else {
    return
}
//x_val available on this scope

Solution 4

One of the most direct ways to use optionals is the following:

Assuming xyz is of optional type, like Int? for example.

if let possXYZ = xyz {
    // do something with possXYZ (the unwrapped value of xyz)
} else {
    // do something now that we know xyz is .None
}

This way you can both test if xyz contains a value and if so, immediately work with that value.

With regards to your compiler error, the type UInt8 is not optional (note no '?') and therefore cannot be converted to nil. Make sure the variable you're working with is an optional before you treat it like one.

Solution 5

From swift programming guide

If Statements and Forced Unwrapping

You can use an if statement to find out whether an optional contains a value. If an optional does have a value, it evaluates to true; if it has no value at all, it evaluates to false.

So the best way to do this is

// swift > 3
if xyz != nil {}

and if you are using the xyz in if statement.Than you can unwrap xyz in if statement in constant variable .So you do not need to unwrap every place in if statement where xyz is used.

if let yourConstant = xyz {
      //use youtConstant you do not need to unwrap `xyz`
}

This convention is suggested by apple and it will be followed by devlopers.

Share:
205,391

Related videos on Youtube

tng
Author by

tng

Swift enthusiast developer. I enjoy writing apps for iOS. Professionally, I work on Microsoft stack.

Updated on July 14, 2022

Comments

  • tng
    tng almost 2 years

    I'm using Xcode 6 Beta 4. I have this weird situation where I cannot figure out how to appropriately test for optionals.

    If I have an optional xyz, is the correct way to test:

    if (xyz) // Do something
    

    or

    if (xyz != nil) // Do something
    

    The documents say to do it the first way, but I've found that sometimes, the second way is required, and doesn't generate a compiler error, but other times, the second way generates a compiler error.

    My specific example is using the GData XML parser bridged to swift:

    let xml = GDataXMLDocument(
        XMLString: responseBody,
        options: 0,
        error: &xmlError);
    
    if (xmlError != nil)
    

    Here, if I just did:

    if xmlError
    

    it would always return true. However, if I do:

    if (xmlError != nil)
    

    then it works (as how it works in Objective-C).

    Is there something with the GData XML and the way it treats optionals that I am missing?

    • Matt Gibson
      Matt Gibson almost 10 years
      Can we see a full example for your unexpected case and error cases, please? (And I know it's hard, but try to start losing the brackets around the conditionals!)
    • newacct
      newacct almost 10 years
      this is changed in Xcode 6 beta 5
    • TonyMkenu
      TonyMkenu almost 10 years
    • tng
      tng almost 10 years
      I just updated the question with the unexpected case.
    • tng
      tng almost 10 years
      I've not updated to beta 5 yet. I will do that soon; nice to see ?? in Swift, and more consistent optional behavior.
  • zaph
    zaph almost 10 years
    The case the OP is concerned about is: if (xyz != nil).
  • Christoph
    Christoph almost 8 years
    Can someone elaborate on why xyz == nil is not working?
  • Lombas
    Lombas almost 8 years
    I find this method to be bad because I create a new variable (constant) unnecessarily, ans having to created a new name that most of the time is gonna be worst than the previous. Takes me more time to write and for the reader.
  • psmythirl
    psmythirl almost 8 years
    In Swift 3 you have to do if xyz != nil {...}.
  • Suhaib
    Suhaib over 7 years
    as mentioned above, you can do this too to get rid of nested optional statmenets. if let abc = abc?.xyz?.something { }
  • Chris Frederick
    Chris Frederick over 7 years
    @Suhaib Ah, true: You can also use optional chaining (developer.apple.com/library/prerelease/content/documentatio‌​n/…) to quickly access nested properties. I didn't mention it here because I thought it might be too much of a tangent from the original question.
  • gnasher729
    gnasher729 about 7 years
    It's the standard method and recommended method to unwrap an optional variable. "'if let " is seriously powerful.
  • gnasher729
    gnasher729 about 7 years
    In Swift 3 optionals cannot be used as boolean. First because it is a C-ism that should never have been in the language in the first place, and second because it causes absolute confusion with optional Bool.
  • Alper
    Alper over 6 years
    The second example should read: // Do something using xy (which is the main difference in use cases between the two variants)
  • user3207158
    user3207158 over 5 years
    @Christoph: The error message is that constant 'xyz' used before being initalized. I think you need to append '= nil' at the end of line of declaration of xyz.
  • Bradley Thomas
    Bradley Thomas about 5 years
    @gnasher729 but what if you only want to use the else part
  • Chris Frederick
    Chris Frederick about 5 years
    @turingtested Thanks! Actually, I think this is programmer friendly in the sense that it guarantees you won't accidentally try to use a nil value, but I agree that the learning curve is a bit steep. :)
  • Omar
    Omar almost 5 years
    For those who are new to swift as I am and are wondering: You still have to unwrap xyz inside the if block. It's safe though, even if you force unwrap
  • Erik Doernenburg
    Erik Doernenburg over 4 years
    @Omar That's the beauty of the second form, you use xy inside the block without having to unwrap it.
  • Andrew___Pls_Support_UA
    Andrew___Pls_Support_UA over 4 years
    xyz == nil expression doesn't work, but x != nil works. Don't know why.
  • thowa
    thowa about 4 years
    I like that, because it gives the easy option to specify a default value.
  • WestCoastProjects
    WestCoastProjects almost 4 years
    It's probably the swift analog of the pythonistas that try to keep the language in some form of pythonic purity . My take? I just lifted your code into my Utils mixin.