希紋的部落格

Swift-Enum基礎

Enum,也稱「列舉」。在不少程式語言上都會有的表示形式,與Class或是Struct不同的是它更像基礎型別的「客製化有限集合」。

不過在Swift中,還保留著Class的部分特性。

參考連結

原文標題寫Swift 3,但我覺得這個基礎型別不太會改動,大部分到Swift5都還繼續使用

基礎

enum Books {
  case computer
  case science
  case langugae
}

宣告完就能直接使用:

let computerType = Book.computer
let computerType :Book = .computer
//宣告func參數
func whichBook( _ type: Book) {}
//使用方式
whichBook(.computer)

方法2和3這邊是使用了Swfit語言的特性,判讀出這個變數的屬性,就能省略直接.出禮面的case

Raw Value

Swift的enum和其他語言不同的是,本身不帶變數,需要明確的定義(implicit)或隱晦(explicit)的定義 case 代表的初始值

enum Books: String {
  case computer
  case science
  case langugae
}

[!NOTE] 假設你給訂的 type 是 String 時, case computer 的 raw value 就是等於 "computer" 。

[!NOTE] 假設有一個 enum 定義的 type 為 Int 的話,那 case 的值就是以 0 開始

除了預設值,也可以為enum定義值:

enum Books: String {
  case computer = "Computer"
  case science = "Science"
  case langugae = "Language"
}

[!NOTE] Int也能改變值,不過後續沒定義到的會自動以前一個case的值+1

使用方法:

let type = Book.computer
print(type.rawValue) // Computer

[!NOTE] CaseIterable定義後,就能使用.allCases將所有定義好的Case都取出來

Enum Associated Value

為直接讓 case 夾帶值,做法是直接在 case 的名稱後面緊接上一個 tuple

enum Error {
    case number(Int)
    case message(String)
}

定義好要帶入參數的type之後就能直接使用對應type的值:

let error : Error = .message("not found")

也能定義參數名稱與帶入多個參數:

enum Error {
    case number(Int)
    case message(String)
    case fatal(num: Int, message: String)
}
let error : Error = .fatal(num: 404, message: "not found")
func retrieve(_ error: Error) {
    switch error {
    case .number(let i):
        print(i)
    case .message(let str):
        print(str)
    case .fatal(num: let I, message: let S):
        print(I, S)
    }
}

retrieve(error) // 404 not found

Error是常用的情境之一,知道錯誤的類型但是需要動態調整錯誤的訊息

Enum Initializer

Swift Enum和其他語言不同的地方就在這,能夠像 Classstruct 一樣,有自己的初始化 function。

enum Book: String {
    case computer
    case science
    case language
    
    static let cases: [Book] = [.computer, .science, .language]
    
    init?(_ ix: Int) {
        guard ix < Book.cases.count else {
            return nil
        }
        self = Book.cases[ix]
    }
}

這樣實例化 case 時,只要使用:

let computer = Book(0)

這時 computer 就會是 Book.computer 的 type 了,但是因為是failable initializer,所以他會是 Optional(Book.computer) 的 type。

是需要用回圈檢查所有型態的場合會用,個人經驗是在建立TableView的時候Cell呈現上有用過。

Enum Properties

另一個不同的地方,就是可以宣告自己的值。

enum ShopType {
    case shopA
    case shopB
    
    var names: [String] {
        switch self {
        case .shopA: return ["A","B","C","D","E","F","G","H","I","J","K","L","M","N","O","P"]
        case .shopB: return ["I","II","III","IV","V","VI","VII","VIII","IX","X"]
        }
    }
}

self的意義就如同class,根據現在的值返回對應的內容

Enum Methods

也能加入func撰寫

enum BookType: String {
    case computer
    case science
    case language
    
    static let cases: [BookType] = [.computer, .science, .language]
    
    init?(_ ix: Int) {
        guard ix < BookType.cases.count else {
            return nil
        }
        self = BookType.cases[ix]

    }
    
    // init without saying rawvalue 
    init?(_ rawValue : String) {
        self.init(rawValue: rawValue)
    }
    
    func nextCase() -> BookType {
        var ix = BookType.cases.index(of: self)
        ix = (ix! + 1) % BookType.cases.count
        return BookType.cases[ix!]
    }
}
var science = BookType("science")
let nextCase = science?.nextCase()

通常會寫在Enum的方法都是跟這個Enum有相關的操作。

結語

文章拆成多個的好處就是能多更新吧,不過我用的平台不需要靠文章數量堆砌,就統一到一起。

這個Enum的操作雖然簡單,不過偶爾也會忘記。

#swift