Search icon CANCEL
Arrow left icon
Explore Products
Best Sellers
New Releases
Books
Videos
Audiobooks
Learning Hub
Conferences
Free Learning
Arrow right icon
Arrow up icon
GO TO TOP
iOS Programming Cookbook

You're reading from   iOS Programming Cookbook Over 50 exciting and powerful recipes to help you unearth the promise of iOS programming

Arrow left icon
Product type Paperback
Published in Mar 2017
Publisher Packt
ISBN-13 9781786460981
Length 520 pages
Edition 1st Edition
Languages
Tools
Arrow right icon
Toc

Table of Contents (16) Chapters Close

Preface 1. Swift Programming Language FREE CHAPTER 2. The Essentials 3. Integrating with Messages App 4. Working with Interface Builder 5. Working with UITableView 6. Animations and Graphics 7. Multimedia 8. Concurrency 9. Location Services 10. Security and Encryption 11. Networking 12. Persisting Data with Core Data 13. Notifications 14. App Search 15. Optimizing Performance

Using error handling

In any iOS project, a lot of operations may fail and you have to respond to these errors in your project. Since Swift 2, a new mechanism has been added to the language for responding and dealing with errors in your project. You can now throw and catch errors when you do any operation that may fail for some reason. Suppose, you do some logic to request some data in a JSON format from a remote server and then you save this data in a local database. Can you imagine how many errors may happen for these operations? Connection may fail between your app and the remote server, failing to parse the JSON response, database connection is closed, database file doesn't exist, or another process is writing in database and you have to wait. Recovering from these errors allows you take the appropriate action based on the error type.

Getting ready

Before starting to learn how to handle errors in Swift, you first have to be familiar with how to represent in errors that are going to happen in your program. Swift provides you with a protocol called ErrorType that your errors types should adopt. Then, to represent errors, here comes the role of enumerations to help you. You create a new enum, which lists all error cases, and this enum should conform to the ErrorType protocol. The syntax of using enum with ErrorType will be something like this:

enum DBConnectionError: ErrorType{ 
  case ConnectionClosed 
  case DBNotExist 
  case DBNotWritable 
} 

As we see it's pretty straightforward. You create enum representing the error that conforms to ErrorType protocol, and then list all errors as cases in the enum.

How to do it...

  1. As usual, let's create a new playground named ErrorHandling.
  2. Let's create now a new error type for a function that will sign up a new user in a system:
      enum SignUpUserError: ErrorType{ 
 
        case InvalidFirstOrLastName 
        case InvalidEmail 
        case WeakPassword 
        case PasswordsDontMatch 
      } 
  1. Now, create the sign up function that throws errors we made in the previous step, if any:
      func signUpNewUserWithFirstName(firstName: String, lastName: String, email: String, password: String, confirmPassword: String) throws{ 
 
        guard firstName.characters.count> 0 &&lastName.characters.count> 0 else{ 
 
          throw SignUpUserError.InvalidFirstOrLastName 
        } 
 
        guard isValidEmail(email) else{ 
          throw SignUpUserError.InvalidEmail 
        } 
 
        guard password.characters.count> 8 else{ 
          throw SignUpUserError.WeakPassword 
        } 
 
        guard password == confirmPassword else{ 
          throw SignUpUserError.PasswordsDontMatch 
        } 
 
        // Saving logic goes here 
 
        print("Successfully signup user") 
 
        } 
 
        func isValidEmail(email:String) ->Bool { 
 
          let emailRegex = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,}" 
          let predicate = NSPredicate(format:"SELF MATCHES %@", emailRegex) 
          return predicate.evaluateWithObject(email) 
        } 
  1. Now, let's see how to use the function and catch errors:
       do{ 
         trysignUpNewUserWithFirstName("John", lastName: "Smith", email: "john@gmail.com", password: "123456789", confirmPassword: "123456789") 
       } 
       catch{ 
         switch error{ 
           case SignUpUserError.InvalidFirstOrLastName: 
             print("Invalid First name or last name") 
           case SignUpUserError.InvalidEmail: 
             print("Email is not correct") 
           case SignUpUserError.WeakPassword: 
             print("Password should be more than 8 characters long") 
           case SignUpUserError.PasswordsDontMatch: 
             print("Passwords don't match") 
           default: 
             print(error) 
         } 
       } 

How it works...

We started our code example by creating a new error type called SignUpUserError, which conforms to ErrorType protocol. As we see, we listed four errors that may happen while signing up any user in our system, such as invalid first name or last name, invalid e-mail, weak password, and passwords that don't match. So far, so good!

Then, we create a function signUpNewUserWithFirstName, which takes user input values, and as we can see, we have marked it with the throws keyword. The keyword throws says that this function may throw an error anytime during execution, so you be prepared to catch errors thrown by this method.

Inside the implementation of the function, you will see a list of guard statements that checks for user input; if any of these guard statements returned false, the code of else statement will be called. The statement throw is used to stop execution of this method and throw the appropriate error based on the checking made.

Catching errors is pretty easy; to call a function that throws error, you have to call it inside the do-catch block. After the do statement, use the try keyword and call your function. If any error happens while executing your method, the block of code inside the catch statement will be called with a given parameter called error that represents the error. We've created a switch statement that checks the type of error and prints a user-friendly statement based on the error type.

There's more...

The information that we previously presented is enough for you to deal with error handling, but still there are a couple of things considered important to be known.

Multiple catch statements

In the preceding example, you will notice that we've created a catch statement, and inside, we used a switch statement to cover all cases of error. This is a correct way, but for your reference, we have another way to do this. Consider the following:

catch SignUpUserError.InvalidFirstOrLastName{ 
 
} 
catch SignUpUserError.InvalidEmail{ 
 
} 
catch SignUpUserError.WeakPassword{ 
 
} 
catch SignUpUserError.PasswordsDontMatch{ 
 
} 

After the do statement, you can list catch statement with the type of error that this statement will catch. Using this method has a condition that the catch statements should be exhaustive, which means it should cover all types of errors.

Disable error propagation

Functions that usually throw an error, in some cases, don't throw an error. In some cases, you may know that calling a function like these with some kind of parameters will never throw an error. In that case, Swift gives you an option to disable error propagation via calling this method with try! instead of try. Calling throwing functions via try! will disable error propagation, and if an error is thrown in that case, you will get a runtime error. So, it's better to take care while using try!.

You have been reading a chapter from
iOS Programming Cookbook
Published in: Mar 2017
Publisher: Packt
ISBN-13: 9781786460981
Register for a free Packt account to unlock a world of extra content!
A free Packt account unlocks extra newsletters, articles, discounted offers, and much more. Start advancing your knowledge today.
Unlock this book and the full library FREE for 7 days
Get unlimited access to 7000+ expert-authored eBooks and videos courses covering every tech area you can think of
Renews at $19.99/month. Cancel anytime