Swift: Testing optionals for nil
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.
Related videos on Youtube
tng
Swift enthusiast developer. I enjoy writing apps for iOS. Professionally, I work on Microsoft stack.
Updated on July 14, 2022Comments
-
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 almost 10 yearsCan 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 almost 10 yearsthis is changed in Xcode 6 beta 5
-
TonyMkenu almost 10 years
-
tng almost 10 yearsI just updated the question with the unexpected case.
-
tng almost 10 yearsI've not updated to beta 5 yet. I will do that soon; nice to see ?? in Swift, and more consistent optional behavior.
-
-
zaph almost 10 yearsThe case the OP is concerned about is:
if (xyz != nil)
. -
Christoph almost 8 yearsCan someone elaborate on why xyz == nil is not working?
-
Lombas almost 8 yearsI 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 almost 8 yearsIn Swift 3 you have to do
if xyz != nil {...}
. -
Suhaib over 7 yearsas mentioned above, you can do this too to get rid of nested optional statmenets. if let abc = abc?.xyz?.something { }
-
Chris Frederick over 7 years@Suhaib Ah, true: You can also use optional chaining (developer.apple.com/library/prerelease/content/documentation/…) 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 about 7 yearsIt's the standard method and recommended method to unwrap an optional variable. "'if let " is seriously powerful.
-
gnasher729 about 7 yearsIn 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 over 6 yearsThe second example should read: // Do something using xy (which is the main difference in use cases between the two variants)
-
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 about 5 years@gnasher729 but what if you only want to use the else part
-
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 almost 5 yearsFor 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 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 over 4 years
xyz == nil
expression doesn't work, butx != nil
works. Don't know why. -
thowa about 4 yearsI like that, because it gives the easy option to specify a default value.
-
WestCoastProjects almost 4 yearsIt's probably the
swift
analog of thepythonistas
that try to keep the language in some form of pythonic purity . My take? I just lifted your code into my Utils mixin.