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

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 
      } 
  1. Use the '.' operator to create enums variables from the previously created enum:
      var monster1 = Monster.Lion 
      let monster2 = Monster.Tiger 
      monster1 = .Bear 
  1. 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.

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" 
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