Book Image

iOS Programming Cookbook

Book Image

iOS Programming Cookbook

Overview of this book

Do you want to understand all the facets of iOS programming and build complex iOS apps? Then you have come to the right place. This problem-solution guide will help you to eliminate expensive learning curves and focus on specific issues to make you proficient at tasks and the speed-up time involved. Beginning with some advanced UI components such as Stack Views and UICollectionView, you will gradually move on to building an interface efficiently. You will work through adding gesture recognizer and touch elements on table cells for custom actions. You will work with the Photos framework to access and manipulate photos. You will then prepare your app for multitasking and write responsive and highly efficient apps. Next, you will integrate maps and core location services while making your app more secure through various encryption methods. Finally, you will dive deep into the advanced techniques of implementing notifications while working with memory management and optimizing the performance of your apps. By the end of the book, you will master most of the latest iOS 10 frameworks.
Table of Contents (22 chapters)
iOS Programming Cookbook
Credits
About the Author
About the Reviewer
www.PacktPub.com
Customer Feedback
Preface

Creating enumerations to write readable code


Using enumerations is one of the best practices that you should follow while writing any software project and not only iOS projects. Once you find that you have a group of related values in your project, create enum to group these values and to define a safe type for these values. With enumerations, your code becomes more readable and easy to understand, as it makes you define new types in your project that map to other value. In Swift, enumerations have been taken care of and have become more flexible than the ones used in other programming languages.

Getting ready

Now, we will dive into enumerations and get our hands dirty with it. To do so, we will create a new playground file in Xcode called Enumerations so that we can practice how to use enumerations and also see how it works.

Writing enumerations is meant to be easy, readable, and straightforward in syntax writing in Swift. Let's see how enum syntax goes:

enum EnumName{ 
} 

You see how it's easy to create enums; your enumeration definition goes inside the curly braces.

How to do it...

Now, let's imagine that we are working on a game, and you have different types of monsters, and based on the type of monster, you will define power or the difficulty of the game. In that case, you have to use enum to create a monster type with different cases, as follows:

  1. Type the following code to create enum with name Monster:

          enum Monster{ 
            case Lion 
            case Tiger 
            case Bear 
            case Crocs 
          } 
     
          enum Monster2{ 
            case Lion, Tiger, Bear, Crocs 
          } 
    
  2. Use the '.' operator to create enums variables from the previously created enum:

          var monster1 = Monster.Lion 
          let monster2 = Monster.Tiger 
          monster1 = .Bear 
    
  3. Use the switch statement to check the value of enum to perform a specific action:

          func monsterPowerFromType(monster:Monster) ->Int { 
        
            var power = 0 
        
            switch monster1 { 
              case .Lion: 
                power = 100 
              case .Tiger: 
                power = 80 
              case .Bear: 
                power  = 90 
              case .Crocs: 
                power = 70 
            } 
            return power 
          } 
     
          let power = monsterPowerFromType(monster1) // 90 
     
          func canMonsterSwim(monster:Monster) ->Bool{ 
        
            switch monster { 
              case .Crocs: 
                return true 
              default: 
                return false 
            } 
          } 
     
          let canSwim = canMonsterSwim(monster1) // false 
    

How it works...

Now, you have a new type in your program called Monster, which takes one value of given four values. The values are defined with the case keyword followed by the value name. You have two options to list your cases; you can list each one of them in a separate line preceded by the case keyword, or you can list them in one line with a comma separation. I prefer using the first method, that is, listing them in separate lines, as we will see later that we can add raw values for cases that will be more clear while using this method.

Note

If you come from a C or Objective-C background, you know that the enums values are mapped to integer values. In Swift, it's totally different, and they aren't explicitly equal to integer values.

The first variable monster1 is created using the enum name followed by '.' and then the type that you want. Once monster1 is initialized, its type is inferred with Monster; so, later you can see that when we changed its value to Bear, we have just used the '.' operator as the compiler already knows the type of monster1. However, this is not the only way that you will use enums. Since enums is a group of related values, so certainly you will use it with control flow to perform specific logic based on its value. The switch statement is your best friend in that case as we saw in the monsterPowerFromType() function.

We've created a function that returns the monster power based on its type. The switch statement checks all values of monster with '.' followed by an enum value. As you already know, the switch statement is exhaustive in Swift and should cover all possible values; of course, you can use default in case it's not possible to cover all, as we saw in the canMonsterSwim() function. The default statement captures all non-addressed cases.

There's more...

Enumerations in Swift have more features, such as using enums with raw values and associated values.

Enum raw values

We saw how enums are defined and used. Enum cases can come with predefined values, which we call raw values. To create enums with raw values, the following rules should be adhered:

  • All raw values should be in the same type.

  • Inside the enum declaration, each raw value should be unique.

  • Only possible values allowed to use are strings, characters, integer, and floating point numbers.

Assigning raw values

When you assign raw values to enum, you have to define the type in your enum syntax and give value for each case:

enum IntEnum: Int{ 
   case case1 = 50 
   case case2 = 60 
   case case3 = 100 
} 

Swift gives you flexibility while dealing with raw values. You don't have to explicitly assign a raw value for each case in enums if the type of enum is Int or String. For Int type enums, the default value of enum is equal to the value of previous one + 1. In case of the first case, by default it's equal to 0. Let's take a look at this example:

enum Gender: Int{ 
   case Male 
   case Female 
   case Other 
} 
var maleValue = Gender.Male.rawValue  // 0 
var femaleValue = Gender.Female.rawValue // 1 

We didn't set any raw value for any case, so the compiler automatically will set the first one to 0, as it's a no set. For any following case, it's value will be equal to previous case value + 1. Another note is that .rawValue returns the explicit value of the enum case. Let's take a look at another complex example that will make it crystal clear:

enum HTTPCode: Int{ 
   case OK = 200 
   case Created  // 201 
   case Accepted // 202 
   case BadRequest = 400 
   case UnAuthorized 
   case PaymentRequired 
   case Forbidden 
    
} 
 
let pageNotFound = HTTPCode.NotFound 
let errorCode = pageNotFound.rawValue  // 404 

We have explicitly set the value of first case to 200; so, the following two cases will be set to 201 and 202, as we didn't set raw values for them. The same will happen for BadRequest case and the following cases. For example, the NotFound case is equal to 404 after incrementing cases.

Now, we see how Swift compiler deals with Int type when you don't give explicit raw values for some cases. In case of String, it's pretty easier. The default value of String enum cases will be the case name itself. Let's take a look at an example:

enum Season: String{ 
   case Winter 
   case Spring 
   case Summer 
   case Autumn 
} 
 
let winter = Season.Winter 
 
let statement = "My preferred season is " + winter.rawValue // "My preferred season is Winter" 

You can see that we could use the string value of rawValue of seasons to append it to another string.

Using Enums with raw values

We saw how easy it is to create enums with raw values. Now, let's take a look at how to get the raw value of enums or create enums back using raw values.

We already saw how to get the raw value from enum by just calling .rawValue to return the raw value of the enum case.

To initialize an enum with a raw value, the enum should be declared with a type; so in that case, the enum will have a default initializer to initialize it with a raw value. An example of an initializer will be like this:

let httpCode = HTTPCode(rawValue: 404)  // NotFound 
let httpCode2 = HTTPCode(rawValue: 1000) // nil 

The rawValue initializer always returns an optional value because there will not be any matching enum for all possible values given in rawValue. For example, in case of 404, we already have an enum whose value is 404. However, for 1000, there is no enum with such value, and the initializer will return nil in that case. So, before using any enum initialized by the rawValue initializer, you have to check first whether the value is not equal to nil; the best way to check for enums after initialization is by this method:

if let httpCode = HTTPCode(rawValue: 404){ 
   print(httpCode) 
} 
if let httpCode2 = HTTPCode(rawValue: 1000){ 
   print(httpCode2) 
} 

The condition will be true only if the initializer succeeds to find an enum with the given rawValue.

Enums with associated values

Last but not least, we will talk about another feature in Swift enums, which is creating enums with associated values. Associated values let you store extra information with enum case value. Let's take a look at the problem and how we can solve it using associated values in enums.

Suppose we are working with an app that works with products, and each product has a code. Some products codes are represented by QR code format, but others by UPC format. Check out the following image to see the differences between two codes at http://www.mokemonster.com/websites/erica/wp-content/uploads/2014/05/upc_qr.png):

The UPC code can be represented by four integers; however, QR code can be represented by a string value. To create an enum to represent these two cases, we would do something like this:

enum ProductCode{ 
   case UPC(Int, Int, Int, Int) 
   case QR(String) 
} 
 
var productCode = ProductCode.UPC(4, 88581, 1497, 3) 
productCode = ProductCode.QR("BlaBlaBla") 

First, UPC is a case, which has four integer values, and the second is a QR, which has a string value. Then, you can create enums the same way we created before in other enums, but here you just have to pass parameters for the enum. When you need to check the value of enum with its associated value, we will use a switch statement as usual, but with some tweaks:

switch productCode{ 
case .UPC(let numberSystem, let manufacturerCode, let productCode, let checkDigit): 
   print("Product UPC code is \(numberSystem) \(manufacturerCode) \(productCode) \(checkDigit)") 
case .QR(let QRCode): 
   print("Product QR code is \(QRCode)") 
} 
 
// "Product QR code is BlaBlaBla"