Getting to Know Enum, Struct and Class Types in Swift

Learn all about enums, structs, and classes in Swift, including value vs reference semantics, dynamic member lookup, and protocol conformance. By Adam Rush.

Leave a rating/review
Download materials
Save for later
Share
Update note: Adam Rush updated this tutorial for Xcode 10, iOS 12 and Swift 4.2. Ray Fix wrote the original.

Back in the days when there was only Objective-C, encapsulation was limited to working with classes. However, in modern iOS and macOS programming using Swift, there are three choices: enums, structs and classes.

Combined with protocols, these types make it possible to create amazing things. While they share many common abilities, these types also have important differences.

The objective of this tutorial is to:

  • Give you some experience using enums, structs and classes.
  • Grant you some intuition about when to use them.
  • Give you an understanding of how each works.

In terms of prerequisites, this tutorial assumes that you have at least the basics of Swift and some object-oriented programming experience. If you want to learn the basics of Swift checkout our Swift Apprentice Book

It’s All About Those Types

Three big selling points of Swift are its safety, speed and simplicity.

Safety implies that it’s difficult to accidentally write code that runs amok, corrupting memory and producing hard-to-find bugs. Swift makes your work safer because it tries to make it obvious when you have a bug by showing you problems at compile time, rather than hanging you out to dry at runtime.

The key to making this happen is the Swift type system:

Diagram showing the six types in Swift

Swift types are powerful, despite there being only six of them. That’s right – unlike many other languages that have literally dozens of built-in types, Swift only has six.

These consist of four named types: protocol, enum, struct and class. There are two compound types as well: tuple and function.

There are those other things that you might think of as basic types, such as Bool, Int, UInt, Float, etc. However, these are actually built up from the named types and delivered as part of the Swift Standard Library.

This tutorial focuses on the so-called named model types, which consist of enum, struct and class.

Shapes With Scalable Vector Graphics (SVG)

As a working example, you’ll build a safe, speedy and simple SVG shape (scalable vector graphics) rendering framework.

SVG is an XML-based vector image format for 2D graphics. This specification has been an open standard developed by the W3C since 1999.

Getting Started

Create a new playground in Xcode to follow along by choosing File ▸ New ▸ Playground… from the menu. Next, choose the platform as macOS and choose the Blank template. Next, name it Shapes and choose a location to save it, then click Create to save the playground. Clear the file completely, then enter the following:

import Foundation

Your goal will be to render something like this:

<!DOCTYPE html>
<html>
  <body>
    <svg width='250' height='250'>
      <rect x='110.0' y='10.0' width='100.0' height='130.0' stroke='teal' 
        fill='aqua' stroke-width='5' />
      <circle cx='80.0' cy='160.0' r='60.0' stroke='red' fill='yellow' 
        stroke-width='5' />
    </svg>
  </body>
</html>

Using a WebKit view, it looks like this:

shapes

You’ll need a representation for colors. SVG uses the CSS3 color type that can be specified as a name, RGB or HSL. For more details, you can read the full specification.

To use a color in SVG, you specify it as an attribute of part of your drawing — for example, fill = 'gray'. An easy approach to this in Swift is to use a String — as in, let fill = "gray".

While using String is easy and does the job, there are some major downsides:

  • It’s error prone. Any strings that are not part of the color spectrum will compile fine but not show up correctly at runtime. For example, “grey” spelled with an “e” doesn’t work.
  • Autocomplete won’t help you find valid color names.
  • When you pass around a color as a parameter, it might not always be obvious that the string is a color.

Using Enums

Using a custom type solves these problems. If you’re coming from Cocoa Touch, you might think to implement an encapsulated class like UIColor. While using a class design could work, Swift gives you more choices for how to define your model.

Without typing anything in just yet, first have a think how you might implement the colors as an enum.

You might think to implement it, like so:

enum ColorName {
  case black
  case silver
  case gray
  case white
  case maroon
  case red
  // etc.
}

The above works very similarly to a set of C-style enums. However, unlike C-style enums, Swift gives you the option to specify a type to represent each case.

Enumerations that explicitly specify a backing store type are referred to as RawRepresentable, because they automatically conform to RawRepresentable.

You can specify the type of ColorName as String, and you assign a value to each case, like so:

enum ColorName: String {
  case black = "black"
  case silver = "silver"
  case gray = "gray"
  case white = "white"
  case maroon = "maroon"
  case red = "red"
  // etc.
}

However, Swift does something special for enums with a String representation. If you don’t specify what the case is equal to, the compiler automatically makes the string the same as the name of the case. That means that you only need to write the case name:

enum ColorName: String {
  case black
  case silver
  case gray
  case white
  case maroon
  case red
  // etc.
}

You can further reduce your typing by separating the cases with commas using the keyword case just once.

Add the following code to the end of your playground:

enum ColorName: String {
  case black, silver, gray, white, maroon, red, purple, fuchsia, green,
    lime, olive, yellow, navy, blue, teal, aqua
}

Now, you have a first-class custom type and all the goodness that comes with that.

let fill = ColorName.grey // ERROR: Misspelled color names won't compile. Good!
let fill = ColorName.gray // Correct names autocomplete and compile. Yay!

CaseIterable

Enums in Swift are great for holding a list of items such as our example list of colors. To make enums even more powerful, Swift 4.2 added a new protocol named CaseIterable that provides a collection of all the values of the conformer.

At compile time, Swift will automatically create an allCases property that is an array of all your enum cases, in the order you defined them.

Using CaseIterable is very simple. All you have to do is declare the conformance in the definition of ColorName as shown below:

enum ColorName: String, CaseIterable {
    case black, silver, gray, white, maroon, red, purple, fuchsia, green, 
      lime, olive, yellow, navy, blue, teal, aqua
}

You can then use the allCases property whose type is [ColorName]. Add the following to the end of your playground:

for color in ColorName.allCases {
  print("I love the color \(color).")
}

In the console, you’ll see 16 lines printed — one for every color in ColorName.