Swift Overview - Enums and Structs

Enums

Primarily used for a collection with a finite set of values

enum PrimaryColor {  
  case red
  case blue  
  case yellow
}

Each case does not need to be indicated by the case word or be on its own line

enum PrimaryColor {   case red, blue, yellow }  

Enums can take on a value of any primitive type, not just integers like in C. The value type must be indicated in enum definition after it’s name

enum PrimaryColor: String {  
  case red = “redColor"
  case blue  = “blueColor"
  case yellow = “yellowColor"
}

To access enum values you can use the built in property .rawValue

var myColor = PrimaryColor.red.rawValue  

Structs

In swift structs are first class citizens. They have capabilities similar to classes in that they can have their own properties, methods, and can extend functionality through extensions and protocols.

In fact most of the commonly used classes like String, Array, Double, and Dictionary are actually structs under the hood.

The two main differences is that structs do not have inheritance like classes. You can not subclass a struct which limits how extensible it can be. And classes live in the heap that we get pointers to them, structs live in the stack and get passed around by making copies of themselves. Objects that get passed around by making copies are Value Types. When objects live in the heap, and we access them by referencing their pointers we call them Reference Types.

The process of making a bunch of copies of a struct might seem cpu intensive but behind the scenes iOS has an elegant way of optimizing how many copies are actually made called copy on write which will actually not make a new copy if there are no changes to the struct, but this is all abstracted away and we generally don't have to worry about it.

struct PictureFrame {  
  var width = 5
  var height = 7
  var thickness: Double = 1.5

   var area: Int {
     get {
         return (width * height)/2
      }
  }
}

Another key difference that is unique to structs is that if we have a func that changes that value of the struct we need to mark it as mutating, which we'll do for the setOperand method.

import Foundation

struct MyModelStruct {

private var accumulator: Double?

func performOperation(_ symbol: String) {
    /* some operation */
}

mutating func setOperand(_ operand: Double) {
    accumulator = operand
}

var result: Double? {
    get {
        return accumulator
    }
}

}

As with enumerations structs can have customized init methods, and also come with automatically generated memberwise initializers

var familyReunionFrame = PictureFrame(width: 10, height: 8, thickness: 1.5)  
familyReunionFrame.area  

Structs can have their own type method, in this case named cheers

struct Beer {  
  var style = "Pale Ale”
  var percentAlcohol = 5.0
  static var cheersDict = ["English": "Cheers!","German": "Prost!", "Japanese": "乾杯", "Mandarin": "干杯!","Russian":"На здоровье!", "Spanish":"Salud!", "Italian": "Cin cin!”]
  var suggestedVolumePerServing:String {
    get {
      let volume: Int = Int(12.0/(percentAlcohol/5.0))
      return "\(volume) ounces”
    }
  }
  static func cheers(_ language: String) {
    if let cheers = cheersDict[language] {
      print("\(cheers)")
    }
  }
}

To initialize the Beer struct we use the automatically generated memberwise initializer passing in the style and percentAlcohol properties

var happyHourBeer = Beer(style:"Lager", percentAlcohol: 6.0)  

To access the computed property we use dot syntax

happyHourBeer.suggestedVolumePerServing  

Because cheers is a type method we call it on the struct itself not the instance, kind of like a class method

Beer.cheers("Japanese")  

It's important to note that if we have a struct where we do not assign a default value but rather just specify the type swift will take it upon itself to initialize the struct by creating a Double in this case and assigning it to percentAlcohol

struct Beer {  
  var percentAlcohol: Double

  var suggestedVolumePerServing:String {
    get {
      return "\(volume) ounces”
    }
  }
}

To avoid this from happening we can make percentAlcohol an optional by changing the var definition to var percentAlcohol: Double? which will assign nil when the struct is initialized.

Structs and Enums

Both structs and enums are value types. This is the key difference between them and classes which are reference types

When a value type like a struct or enum is assigned to a variable or a constant it’s copied, an entirely new instance is created. When a reference type is assigned to a variable or content there is not a copy made, instead a new reference to the original instance is created.

var frame = PictureFrame(width: 3, height: 5, thickness: 0.5)  
var frameForMom = frame  
frameForMom.width = 5  
frameForMom.height = 7  

When we look at the output from the above example frame.width is equal to 3 and frame.width is still equal to 5 because frameForMom is an entirely new copy of the PictureFrame struct