When Two Optionals Are Assigned to an If Let Statement, Which One Gets Unwrapped? Swift Language

Swift optionals and if let statement

When you do

if let num = Int(numTextField.text!){}

It will unwrap the value for you and check if it can set the value of textfield to num. If the value is nil you will be able to handle the error like this

if let num = Int(numTextField.text!){
print("Yes the value is not nil")
}else{
print("Couldn't assign value to num because it's nil")
}

If you do

var num = Int(numTextField.text!)!

and the textfield is nil, you will get a runtime error and your app will crash.

Unwrapping Optionals (Swift Playground)

As you know, () can be used to surround an expression and it will have no effect on the evaluation of that expression, and you are asking "why can't I do the same to let forSureNames = strArray?" Right?

This is because let forSureNames = strArray is not an expression. You are parsing this statement wrong. The word let is part of the if let statement.

You are confusing if let statements with C-style if statements, where after the if, there is always an expression that evaluates to Bool. if let simply does not work like that. It takes the form:

if let <identifier> = <expression> { }

where expression must evaluate to an optional type. So putting () around let <identifier> = <expression> makes little sense. You could put () around strArray because that is an expression, but I don't see the point of that.

How does the '?' unwrap an optional in a case let declaration?

This is syntactic sugar for option patterns. The docs on option pattern says:

An optional pattern matches values wrapped in a some(Wrapped) case of an Optional<Wrapped> enumeration. Optional patterns consist of an identifier pattern followed immediately by a question mark and appear in the same places as enumeration case patterns.

Thus, your code is the same as:

var x: Int? = 42

if case .some(let a) = x {
print(a)
}

It's not typical for simple if statements as you can just do this instead:

if let a = x {
print(a)
}

But consider an enum wrapped in an optional:

enum Foo {
case bar
case baz
}

let y: Foo? = .bar

switch y {
case .none: break
case .some(.bar): break
case .some(.baz): break
}

This switch can be written in a more succinct way using some sugar:

switch y {
case nil: break
case .bar?: break
case .baz?: break
}

Unwrapping optionals to a pre-defined variable in the guard condition without creating a new constant

I would just test for nil and then force unwrap when I know it's not:

var someString: String? = "hello"
let nonOptionalString: String // note, you don't have to initialize this with some bogus value

guard someString != nil else { return }
nonOptionalString = someString!

Or if someString was a parameter to some method or closure, you can unwrap in the guard statement using the same variable name, simplifying life even more:

func foo(someString: String?) {
guard let someString = someString else { return }

// now I can just use local `someString`, which is not optional anymore
}

If you're desperate to unwrap and exit-if-nil in a single statement, you could theoretically write a function to unwrap if it can or throw an error if it can't:

extension Optional {
enum OptionalError: Error {
case unwrapFailed
}

func unwrap<T>() throws -> T {
if self == nil { throw OptionalError.unwrapFailed }
return self as! T
}
}

Then you can do:

do {
firstNonOptional = try firstOptional.unwrap()
secondNonOptional = try secondOptional.unwrap()
thirdNonOptional = try thirdOptional.unwrap()
} catch {
return
}

I think that's horrible overkill, but if you're desperate to distill it down to one line per unwrap, that's one way to do it.

swift if let statement with as?,but why use question mark?

Your code:

if let foo = object as? String

breaks into two significant parts: object as? String and if let.

The first is a downcast which allows for failure by producing an optional type (String? here). From The Swift Programming Language (Swift 3.1): Typecasting:

Use the conditional form of the type cast operator (as?) when you are not sure if the downcast will succeed. This form of the operator will always return an optional value, and the value will be nil if the downcast was not possible. This enables you to check for a successful downcast.

The second, if let, is an optional binding which unwraps an optional, the body of the if let is only executed if the optional value being unwrapped is not nil and with the bound variable being bound to the unwrapped value. See Optional Binding in The Swift Programming Language (Swift 3.1): Basics.

So your sense that something is happening twice here is correct. The as? cast may fail and produce a nil optional value, the if let will test that optional value for nil. We can only hope that the compiler handles the combination of if let and as? together and no unneccesary optionals are actually created and destroyed by the implementation.

HTH

Swift unwrapping for multiple optionals

If you're attempting to print the non-nil values as a comma-separated list, then I think @MartinR's suggestion of using flatMap() is the best:

let one: String?
let two: String?
let three: String?

one = "one"
two = nil
three = "three"

let nonNils = [one, two, three].flatMap { $0 }
if !nonNils.isEmpty {
print(nonNils.joinWithSeparator(","))
}

Output:

one,three

Swift: guard let vs if let

if let and guard let serve similar, but distinct purposes.

The "else" case of guard must exit the current scope. Generally that means it must call return or abort the program. guard is used to provide early return without requiring nesting of the rest of the function.

if let nests its scope, and does not require anything special of it. It can return or not.

In general, if the if-let block was going to be the rest of the function, or its else clause would have a return or abort in it, then you should be using guard instead. This often means (at least in my experience), when in doubt, guard is usually the better answer. But there are plenty of situations where if let still is appropriate.

How is Swift `if let` evaluated?

Essentially the line is saying, "if you can let the new variable name equal the non-optional version of optionalName, do the following with it". As Martin pointed out, this is called Optional Binding.

The sole purpose of it is to test if an optional variable contains an actual value and bind the non-optional form to a temporary variable. This is the safe way to "unwrap" an optional or in other words, access the value contained in the optional. It is in no way testing for equality of any kind. It is only testing for the existence of a value within an optional.

Would you ever use the value assigned in a if let statement

In this example No , but imagine a situation where you want to do 10 tasks with the name and pass it to multiple functions, in those cases yes.If you don't use it you have to write an if check for every single of those tasks and functions (because an optional causes other methods return value to be optional as well) which makes your code less readable and complicated without any reason.

Imaging 10

if name?.somefunction() != nil { 
// do something if it is available
}else{
// it's not available. Do something appropriate
}


Related Topics



Leave a reply



Submit