Tuesday, April 4, 2017

Swift Don’t use forced unwrapping !

In this post, Let’s see what happens If we forced unwrap things and the crashes that it creates.

Let me take 3 simple classes.

  1. User
  2. UserAccount
  3. WishList
class User {
    var name: String?
    var account: UserAccount?
}

class WishList {
    var totalItems: Int = 0
}

class UserAccount {
    var status: String?
    var items: [WishList]?
}

Here I want to check the account of the user. Then only we need to check the wish list of the user and notify if items are available in the wish list.

I am creating user instance and passing it to a function which checks user’s account first and then wish list and then notifies the user on items availability.

let user: User = User()
user.name = "Karunakar Bandikatla"

checkForCartItemsAndNotifyItemsAvailability(user: user)

func checkForCartItemsAndNotifyItemsAvailability(user: User) {
        
}

First, I need to check user’s account optional value.
What If we forced unwrap and access user’s account object.

func checkForCartItemsAndNotifyItemsAvailability(user: User) {
    let account: UserAccount = user.account!
}

Application gets crashed with a fatal error.

fatal error: unexpectedly found nil while unwrapping an Optional value

This is because, we haven’t assigned UserAccount object for user.

I am assigning it now.

let userAccount: UserAccount = UserAccount()
user.account = userAccount

If we run the app, It will not get crashed. To avoid this crash, What we can do is, We can check with If let as shown below

func checkForCartItemsAndNotifyItemsAvailability(user: User) {

      if let account = user.account {

      }
}

Like this we are checking the optional user account object and proceeding only if the value is not nil.

For checking a single object is fine using If lets. What If we have chain of objects need to be checked like in our example.

  1. User’s account should be checked
  2. User’s wish list object should be checked 

In handling chain of optional objects, guard helps a lot in checking all the optional nil conditions in a single statement and returning the function execution If any of the optionals are nil.

Let me show you how.

func checkForCartItemsAndNotifyItemsAvailability(user: User) {

        guard let account = user.account,
                 let wishlist = account.items else{
                    print("something is missing!")
                return
        }

        if wishlist.count > 0 {
            print("notify user")
        }
}


Thus we are checking all the chain the optional objects in a single guard statement and If any of the condition doesn’t met returning in guard else block. That’s how guard avoids all the optional nil crashes.

Don’t go for Forced Unwrapping, It will crash the app one way or other in any unchecked scenario.

Go for IfLet for a single object check and go for guard for chain of objects check.


Hope this post is useful. Feel free to comment incase of any queries.