Search This Blog

Tuesday, February 6, 2018

iOS Swift. All ways to unwrap optional

There I want to enumerate all possible ways to unwrap optional variables that possible in Swift.

  1. Force Unwrapping
  2. Check for nil (with !=) and Force Unwrapping
  3. Ternary Operator
  4. if let Construction or Single Optional Binding
  5. Multiple Optional Binding
  6. Guard Operator
  7. Nil Coalescing Operator
  8. Switch Operator
  9. Optional Chaining

Let's review each of them.


Force Unwrapping


When you have optional and you are sure that this optional has a value you always can just use force unwrapping with ! (exclamation point operator). But it always for your responsibility use this because there can be situations when optional will have no value and force unwrapping will produce error and app crashing.
let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]
let name1 = dict[1]
let name4 = dict[4]
print(name1!) // "Jack"
print(name4!) // Fatal error: Unexpectedly found nil while unwrapping an Optional value

Check for nil


But there is solution for ensure from errors when using force unwrapping - just check optional for nil before that.
let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]

print(dict[1]) // Optional("Jack")
print(dict[4]) // nil

func getName(for index: Int) -> String {
    if dict[index] != nil {
        return dict[index]!
    }
    return "No name for such index"
}

print(getName(for: 1)) // "Jack"
print(getName(for: 4)) // No name for such index

Ternary Operator


The same check for nil can be done with ternary operator.
let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]

print(dict[1]) // Optional("Jack")
print(dict[4]) // nil

func getName(for index: Int) -> String {
    return dict[index] != nil ? dict[index]! : "No name for such index"
}

print(getName(for: 1)) // "Jack"
print(getName(for: 4)) // No name for such index

if let Construction or Optional Binding


This construction if let allows you safety unwrap optional value. If optional has value then this value will be unwrapped to constant/variable. Unwrapped variable/constant will be available only in scope inside this if let statement.
let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]

print(dict[1]) // Optional("Jack")
print(dict[4]) // nil

func getName(for index: Int) -> String {
    if let name = dict[index] {
        return name
    }
    return dict[index] ?? "No name for such index"
}

print(getName(for: 1)) // "Jack"
print(getName(for: 4)) // No name for such index

Multiple Optional binding


There can be optional property of optional object, so you can do some chaining of if let statements. All this if let statements can be written in on line with one if and with commas. Every next statement will be executed only if previous value is unwrapped.
struct A {
    let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]
    func getName(for index: Int) -> String? {
        return dict[index]
    }
}

struct B {
    var names: A?
    
    init() {
        self.names = A()
    }
}

let b: B? = B()

if let b = b {
    if let names = b.names {
        if let name = names.getName(for: 1) {
            print(name) // Jsck
        }
    }
}

if let b = b, let names = b.names, let name = names.getName(for: 1) {
    print(name) // Jack
}

Guard Operator


Guard operator or "Early Exit" check that optional has value and can be unwrapped. If optional has no value then else statement will be executed. Unwrapped value will be available in scope next to guard, opposite to if let statement.
let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]

print(dict[1]) // Optional("Jack")
print(dict[4]) // nil

func getName(for index: Int) -> String {
    guard let name = dict[index] else {
        return "No name for such index"
    }
    return name
}

print(getName(for: 1)) // "Jack"
print(getName(for: 4)) // No name for such index

Nil Coalescing Operator or ??


Special operator ?? works following way: if there is a value in optional then this value will be return else default value will be return.
let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]

print(dict[1]) // Optional("Jack")
print(dict[4]) // nil

func getName(for index: Int) -> String {
    return dict[index] ?? "No name for such index"
}

print(getName(for: 1)) // "Jack"
print(getName(for: 4)) // No name for such index

Switch Operator


We can use switch operator for unwrapping optionals because if we open source code of Optional we can see that Optional is an enum with 2 cases: none and some.
public enum Optional<Wrapped> : ExpressibleByNilLiteral {
    case none
    case some(Wrapped)
}

In case of .none - there is no value (it means nil). In case of .some - there is a value that we can use and this value will be unwrapped.
let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]

func getName(for index: Int) -> String {
    let name =  dict[index]
    switch name {
    case .some(let value):
        return value
    case .none:
        return "No name for such index"
    }
}

print(getName(for: 1)) // Jack
print(getName(for: 4)) // No name for such index

Optional Chaining


In some cases optional instance of struct or class can have optional properties. So, when we need to get optional property of optional object it is a chain of optionals. Every next optional value will be unwrap only if previous is can be unwrapped. For, example
b?.names?.getName(for: 1)?.count
Property count will be getting only if b can be unwrapped, names can be unwrapped and value which will be returned by getNames() can be unwrapped too. If any of values in chain cannot be unwrapped then property count will be nil.
struct A {
    let dict = [1: "Jack", 2: "John", 9: "Kate", 77: "Charlie"]
    func getName(for index: Int) -> String? {
        return dict[index]
    }
}

struct B {
    var names: A?
    
    init() {
        self.names = A()
    }
}

let b: B? = B()
b?.names?.getName(for: 4)?.count

print(b?.names?.getName(for: 1)?.count) // Optional(4) because "Jack" has 4 letters
print(b?.names?.getName(for: 4)?.count) // nil because no name for such index

6 comments:

  1. Your article is one of its kind which explained every bit of Custom Build Website. looking for further valuable articles from you

    ReplyDelete
  2. Great content. I was looking for this kind of content. It saved my time to search further.
    You must provide such type of content constantly. I appreciate your willingness to provide readers with a good article.
    Custom Design Websites

    ReplyDelete
  3. Thank you Sir, you made it easy as pie. Now i am able to understand and have enough knowledge about this. It is only because of you.
    Custom Designed Websites

    ReplyDelete
  4. This is a great article! Thank you very much. I really need these suggestions. An in-depth explanation is of great benefit. Incredibly inspiring to see how you write. Custom Website

    ReplyDelete
  5. Great content. I was looking for this kind of content. It saved my time to search further.
    You must provide such type of content constantly. I appreciate your willingness to provide readers with a good article.
    Mobile Performance Meter Hack

    ReplyDelete
  6. This is an excellent article. Your essay is very easy to understand. Thank you for providing us with this useful information.
    SEO Company NYC

    ReplyDelete