Swift. Best way to get Int from Int?

Viewed 116

I just started learning Swift and I'm still confused about Optionals. I was wondering, what's the best way of doing it or what way should I follow?

let arrayOptional : [Int?] = [25, 30, nil, 50, nil]
// Optional Binding
var sum = 0
for i in arrayOptional {
    if let temp = i {
        sum += temp
    }
}
sum = 0

// Forced Unwrapping
for i in arrayOptional {
    if i != nil {
        sum += i!
    }
}
sum = 0

// ?? operator
for i in arrayOptional {
    sum += i ?? 0
}

So are there any benefits of using one method over another?

3 Answers

What you can do, it's use compactMap function, so you will get the non-nil values from arrayOptional and then use reduce function to get result

sum = arrayOptional.compactMap{ $0 }.reduce(0, +)

You unwrap it either using if let or guard... else.

//If let would be optimal for your example because you are not doing much after unwrapping 
for i in arrayOptional {
    if let temp = i {
        sum += temp
    }
}

// guard...else would be useful when you have a lot to do and you don't want to keep on nesting code inside {}
for i in arrayOptional {
    guard let temp = i else {
        continue
    }
    sum += temp
}

Force unwrapping (!) is only done when you want the app to crash or when you are certain that the optional will not contain nil. eg: Dequeuing a cell, UITextfield's and UITextView's text property is an optional but will never be nil.

The nil coalescing operator (??) provides a default value in case your optional turns out to nil. You use it while assigning an optional to a non-optional variable.

You can simply use a reduce to get the sum.

let sum = arrayOptional.reduce(into: 0, {$0 += $1 ?? 0})

In general, you should use optional binding (your first approach) or the nil coalescing operator (your last approach) for safely unwrapping optionals, nil check and then force unwrapping is not the recommended approach.

If you want to stick with a loop approach, you can make it simpler using pattern matching in the loop variable declaration (the body of the loop will only be executed for non-nil values in arrayOptional):

var sum = 0
for case let i? in arrayOptional {
    sum += i
}
Related