swift

Enumerations, for C ++ programmers, are easy to understand and to use: it is a group of homogeneous constants that can be used, for example, in the switch constructor to select the various cases. An example may be the following:

enum productionPhases { Start, Cycle1, Cycle2, End, Wait };
productionPhases phases;

switch (phases) {
  case Start: //Do something
    break;
  case Cycle1: //Do something
    break;
  case Cycle2 : //Do something
    break;
  case End : //Do something
    break;
  case Wait :
    break;
}

In Swift, enumerations bring greater functionality. The definition provided in the Swift manual may seem cryptic:  “An enumeration defines a common type for a group of related values and enables you to work with those values in a type-safe way within your code”. It is a prelude to a very large use of enumerations, where they are thought to be a safe environment for operations.

In other words, enumerations are no longer just a set of homogeneous values but are closer to the class concept in which computed properties and methods can exist. As with classes, their capabilities can be extended through extensions.

In their simpler exposure enumerations can be defined as in the following example:

enum ProductionPhases {

    case start

    case execution

    case wait

    case end

}

 

In the example we have a production cycle identified by the four phases enumerated through the case statement. I must point out that in the enumerations in C or C ++ each value is associated with an integer that acts as an index; in Swift this is not true.

Swift enumerations are a real-user-defined type, so for the convention used in Swift the name must begin with a uppercase letter. More generally, the names of types and protocols follow the "UpperCamelCase" convention (eg MyType), while the rest "lowerCamelCase" (eg myVariable).

var currentPhase = ProductionPhases.execution

currentPhase = .wait

 

Once the enumerative type has been assigned to a Swift variable, as in the above example to the currentPhase variable, reassigning a value to the variable no longer has to write the entire name of the enumerative type, simply indicate the single case. With enumerative types we can use the switch construct.

switch currentPhase {

    case .start:

        print("start")

    

    case .execution:

        print("execution")

    

    case .wait:

        print("wait")

    

    case .end:

        print("end")

}

 

It is important to note that if all the cases of the currentPhase type are not listed in the switch block, the compiler returns an error. To prevent this, you must enter the default case. Another important note is the absence of break instruction after each case.

Let's resume the enumerative definition of the above-mentioned ProductionPhases and suppose we need more information; For example, let's say that at the execution stage we want to know what level of execution we've got, or in the waiting phase how many seconds are missing to the job resume, finally in the final stage have the outcome of the production. All this can be done within the enumerative type. We change the definition of ProductionPhases:

enum ProductionPhases {

    case start

    case execution(String)

    case wait(Int)

    case end(String)

}

var currentPhase = ProductionPhases.start

 

With this ProductionPhases statement we imposed a three-element constraint. The execution element brings with it additional String information, instead wait brings int type. Then it is created the currentPhase variable with an initial value. In the next code, with switch we will give meaning to these values.

switch currentPhase {

    case .start:

        //I'm setting the currentPhase value so the next turn next case is selected,

        //then I'm setting the String value of execution.

        currentPhase = .execution("Assembly started")

    case .execution(let level):

        //At the first pass the first statement is executed and it is changed 
        //the string content of execution case so at the next turn 

        //a different currentPhase will be set
.

        if level == "Assembly started" {

            currentPhase = .execution("Assembly end")

        }

        else if level == "Assembly end" {

            currentPhase = .wait(60)

        }

    case .wait(var time):

        //... here I'm executing some actions to get the 'time' variable to zero ...

        //than I'm setting currentPhase to pass to the next case

        if time == 0 {

            currentPhase = .end("Production OK")

        }

    case .end(let result):

        if result == "Production OK" {

            print("end")

        }

        else {

            print("Error in production")

        }

}

 

To get the example working you have to suppose that there is an external function that repeatedly calls the portion of code above.

At each cycle, the value of the variable currentPhase is updated so that a different portion of code is executed in the next cycle. It is straightforward to see that after a finite number of cycles you will come to the result of seeing the word "end" printed.

The interesting thing is that during the first cycle to the enumerative type ProductionPhases.execution is assigned a value string that is "Assembly started". In the next cycle when the .execution case is reached, the previously assigned value is retrieved with the let statement and the name level. At this point, the level is interrogated to get the "Assembly started" value and run the relevant code. This procedure is repeated in the following cycles.

In brief:

  • You can add to each element of enum its own type.
  • You can assign a value to that element via the associated variable.
  • You can recall the value above assigned by switch and the keywords let and var.