對於枚舉原始值,系統默認只能是字符串、整型、浮點型字面量,那麼咱們能不能增長其它類型呢?swift
答案是能夠的,經過協議RawRepresentable就能夠實現xcode
首先定義一個枚舉函數
enum Terrain: String {
case forest = "F"
case mountain = "M"
case water = "W"
}
複製代碼
該協議定義了一個初始化構造器,當傳入無效的原始值時構造器會返回nil;還定義了一個rawValue計算屬性。ui
當定義上述枚舉時,編譯器將生成以下等價的代碼:spa
enum Terrain {
case forest
case mountain
case water
}
extension Terrain: RawRepresentable {
typealias RawValue = String
init?(rawValue: RawValue) {
switch rawValue {
case "F": self = .forest
case "M": self = .mountain
case "W": self = .water
default: return nil
}
}
var rawValue: RawValue {
switch self {
case .forest: return "F"
case .mountain: return "M"
case .water: return "W"
}
}
}
複製代碼
rawValue本質是一個計算屬性.net
enum Terrain: String {
case forest = "F"
case mountain = "M"
case water = "W"
}
let tt = Terrain.forest
print(tt.rawValue)
複製代碼
0x104e32fe2 <+130>: movq %rdx, -0x50(%rbp)
0x104e32fe6 <+134>: callq 0x104e330b0 ; Test.Terrain.rawValue.getter : Swift.String at <compiler-generated>
0x104e32feb <+139>: movq 0x6056(%rip), %rsi ; (void *)0x00007fff879c41c8: type metadata for Swift.String
複製代碼
經過斷點調試彙編能夠看到,底層call調用了rawValue的getter方法調試
而對rawValue進行賦值則會報錯rest
let tt = Terrain.forest
tt.rawValue = "M" //Cannot assign to property: 'rawValue' is immutable
複製代碼
一、原始值是不會存儲到枚舉變量中去的,而且只佔用一個字節(嚴格的說當枚舉成員個數小於256)code
方法(1)經過函數MemoryLayout能夠驗證blog
MemoryLayout.size(ofValue: Terrain.forest) // → 1個字節
MemoryLayout.size(ofValue: "F") // → 16個字節
複製代碼
方法(2)經過xcode調試View Memory能夠查看枚舉變量在內存中具體存放的內容(已有很多文章介紹,就不細說了)
RawRepresentable的RawValue關聯類型能夠是任何類型,前提是字面量,即它們在編譯時必須是靜態已知的。
而且實際原始值能夠在運行時動態建立。舉一個用於顏色的枚舉示例:
import UIKit
// 默認這裏不能直接用UIColor做爲原始值
enum Color {
case red
case green
case blue
}
// 經過遵照協議RawRepresentable能夠把UIColor做爲原始值
extension Color: RawRepresentable {
typealias RawValue = UIColor
init?(rawValue: RawValue) {
switch rawValue {
case UIColor.red: self = .red
case UIColor.green: self = .green
case UIColor.blue: self = .blue
default: return nil
}
}
var rawValue: RawValue {
switch self {
case .red: return UIColor.red
case .green: return UIColor.green
case .blue: return UIColor.blue
}
}
}
// 可使用UIColor
Color.blue.rawValue is UIColor
複製代碼
一、RawRepresentable協議不單單用在枚舉上,還有Swift中的選項集合OptionSet(該協議繼承自RawRepresentable),應用於位掩碼操做
二、原始值和關聯值是不一樣的;原始值是在定義枚舉時被預先填充的值,像上述三個字符串。對於一個特定的枚舉成員,它的原始值始終不變。關聯值是建立一個基於枚舉成員的常量或變量時才設置的值,枚舉成員的關聯值能夠變化。底層以及應用它們的區別還有不少,這裏就不細說了。