We know that we can use an if let
statement as a shorthand to check for an optional nil then unwrap.
However, I want to combine that with another expression
In Swift 3 Max MacLeod's example would look like this:
if let tabBarController = window!.rootViewController as? UITabBarController, tabBarController.viewControllers.count > 0 {
println("do stuff")
}
The where
was replaced by ,
It is not possible.
From Swift grammar
GRAMMAR OF AN IF STATEMENT
if-statement → if if-condition code-block else-clauseopt
if-condition → expression | declaration
else-clause → else code-block | else if-statement
The value of any condition in an if statement must have a type that conforms to the BooleanType protocol. The condition can also be an optional binding declaration, as discussed in Optional Binding
if-condition must be expression or declaration. You can't have both expression and declaration.
let foo = bar
is a declaration, it doesn't evaluate to a value that conforms to BooleanType
. It declares a constant/variable foo
.
Your original solution is good enough, it is much more readable then combining the conditions.
As of Swift 1.2, this is now possible. The Swift 1.2 and Xcode 6.3 beta release notes state:
More powerful optional unwrapping with if let — The if let construct can now unwrap multiple optionals at once, as well as include intervening boolean conditions. This lets you express conditional control flow without unnecessary nesting.
With the statement above, the syntax would then be:
if let tabBarController = window!.rootViewController as? UITabBarController where tabBarController.viewControllers.count > 0 {
println("do stuff")
}
This uses the where
clause.
Another example, this time casting AnyObject
to Int
, unwrapping the optional, and checking that the unwrapped optional meets the condition:
if let w = width as? Int where w < 500
{
println("success!")
}
For those now using Swift 3, "where" has been replaced by a comma. The equivalent would therefore be:
if let w = width as? Int, w < 500
{
println("success!")
}
Swift 4, I will use,
let i = navigationController?.viewControllers.index(of: self)
if let index = i, index > 0, let parent = navigationController?.viewControllers[index-1] {
// access parent
}
I think your original proposition is not too bad. A (messier) alternative would be:
if ((window!.rootViewController as? UITabBarController)?.viewControllers.count ?? 0) > 0 {
println("do stuff")
}
Max's answer is correct and one way of doing this. Notice though that when written this way:
if let a = someOptional where someBool { }
The someOptional
expression will be resolved first. If it fails then the someBool
expression will not be evaluated (short-circuit evaluation, as you'd expect).
If you want to write this the other way around it can be done like so:
if someBool, let a = someOptional { }
In this case someBool
is evaluated first, and only if it evaluates to true is the someOptional
expression evaluated.