moroz.dev

<< Back to index

Learning iOS and Swift. Day 5: Enums

Abstract

Quick introduction to things you can do with Swift enumerations.

Swift comes with a feature-rich system of data types, including enumerations, structs and classes. All of these are quite similar to their Rust counterparts, except that in Rust, there are no classes. Today I introduce some facts about enumerations, also known as enums.

In order to be able to quickly test Swift scripts, I defined a keybinding to run the script inside Neovim:

nnoremap <Leader>mr :vert ter swift %<CR>a

A Swift enumeration, in its simplest form, is defined with just a name and cases. Its values are abstract values with no rawValue property:

enum Status {
    case success, failure, unknown
}

print(Status.success)
// success

You can get a string representation of the enum label using String(describing:):

let asString = String(describing: Status.unknown)
print(asString.uppercased())
// UNKNOWN

You can also define an enum to correspond to a raw value, like a string or a number. If you just define an enum with an Int type, it will assign consecutive integer values, starting from 0:

enum Implicit: Int {
    case first
    case second
}

print(Implicit.first.rawValue)
// 0
print(Implicit.second.rawValue)
// 1

You can also define a staring value for one of the values, and the following cases will increment, starting from that value:

enum StatusCode: Int {
    case OK = 200
    case Created, Accepted, NonAuthoritativeInformation, NoContent
}

print(StatusCode.Created.rawValue)
// 201
print(StatusCode.NoContent.rawValue)
// 204

With String values, you need to define each value:

enum Role: String {
    case regular = "REGULAR"
    case admin = "ADMIN"
}

let adminRole = Role.admin
print(adminRole.rawValue)
// ADMIN
print(String(describing: adminRole))
// admin

Converting from raw value to enum

You can convert a raw value to enum using an initializer with rawValue (init(rawValue:)). The initializer returns an Optional, since the operation may fail:


// casting String to enum
if let fromString = Role(rawValue: "ADMIN") {
    print(fromString)
    // admin
}

let willFail = Role(rawValue: "NO CAN DO")
print(willFail as Any)
// nil

Methods and computed properties

Enums, just like classes and structs, can have methods and computed properties.

// Foundation extends String with the `capitalized`
// computed property
import Foundation

// defining an enum with corresponding String values
enum FellowshipMember: String {
    case gandalf = "You shall not pass!"
    case frodo = "Okay, then. Keep your secrets."

    // a method
    func showYourself() {
        let label = String(describing: self).capitalized
        print("\(label) said, \"\(self.rawValue)\"")
    }

    // a computed property needs to be defined with `var`
    var spongeBobCased: String {
        let converted = self.rawValue.unicodeScalars.enumerated().map { (index, char) -> String in
            let str = String(char)
            if index % 2 == 0 {
                return str.lowercased()
            } else {
                return str.uppercased()
            }
        }
        return converted.joined()
    }
}

print(FellowshipMember.gandalf.spongeBobCased)
// yOu sHaLl nOt pAsS!
print(FellowshipMember.frodo.spongeBobCased)
// oKaY, tHeN. kEeP YoUr sEcReTs.

FellowshipMember.frodo.showYourself()
// Frodo said, "Okay, then. Keep your secrets."
FellowshipMember.gandalf.showYourself()
// Gandalf said, "You shall not pass!"