Swift枚舉熟練運用必備知識

Swift中的枚舉有原始值和關聯值,其使用范圍相比OC來說多了很多,因此也更復雜,需要我們花更多的時間來學習它,本文是對學習后和在實際中的運用做的一個總結。
目前來看需要掌握的內容如下:

Swift枚舉內容.jpg

一、Swift枚舉聲明
>>> A. 枚舉的類型及原始值、關聯值
    1. 聲明枚舉時,類型繼承列表(即冒號后面)寫原始值類型,不寫時默認是Int,如果是其它類型則需要寫明。
    1. 原始值代表的是一個枚舉變量的rawValuerawValue的本質是枚舉的計算屬性
    1. 在寫枚舉的case時:
      如果原始值類型是IntString類型,不寫明原始值會自動生成原始值, 對于Int類型默認從0開始,下一個是上一個case的原始值+1;對于String類型,默認原始值是case名;
      如果是其它原始值類型的枚舉,可以用"="寫明對應的原始值,見下面的Direction.
    1. 每個case后面可以追加枚舉關聯值,比如下面的Score.
    1. 遞歸枚舉:如果枚舉關聯值中有枚舉本身類型,則這個時候在枚舉定義前或者case前需要加indirect
    1. 枚舉變量初始化時使用一般使用enumName.caseName
    1. 枚舉默認遵守RawRepresentable協議,協議里面有可失敗初始化器init?(rawValue: Self.RawValue)和計算屬性rawValue. 所以我們可以通過這個協議的方法來完成初始化和獲取原始值rawValue
    1. 枚舉的原始值類型必須是可以用字面量表示的,比如IntFloatString等, 不然的話會報錯Raw value for enum case must be a literal.
    1. 枚舉的case不能即寫明原始值又寫關聯值,寫了報錯Enum with raw type cannot have cases with arguments
// 1.這里的原始值類型是Character,如果不寫明= "d"則會報錯. 
// 2.如果是不寫原始值類型Character,默認是Int。
// 3.對于原始值類型是Int或者String,不寫明“=”后面的也不會報錯。
enum Direction: Character { 
    case north = "d"
    case south = "s"
    case east = "e"
    case west = "w"
}

// 帶枚舉關聯值的枚舉
enum Score {
    case point(Int, Int, Int)
    case grade(Character)
}

// case中關聯值有自身枚舉類型的遞歸枚舉
indirect enum ArithExpr {
    case number(Int)
    case sum(ArithExpr, ArithExpr)
    case difference(ArithExpr, ArithExpr)
}
>>> B. 枚舉的其它性質

Swift中枚舉可以遵守協議,可以添加成員方法、靜態方法、靜態變量、計算屬性。

enum BasketballNum4: Character, CaseIterable {
    case AAAA16 = "2"
    // 可添加計算屬性
    var name: String { "dandy" }
    // 可添加靜態變量
    static var name2: String { "dandy.static" }
    // 可添加成員方法
    func testSelf() {
        print(self.name)
        print(Self.name2)
    }
    // 可添加靜態方法
    static func testSelf2() {
        print(self.name2)
    }
}
二、枚舉變量的內存

弄清楚枚舉的內存使用情況能讓我們在使用時對性能消耗有所了解。
使用MemoryLayout可以查看分配內存和使用內存情況,比如下面的方式:

    print("MemoryLayout<String>.size", MemoryLayout<String>.size)
    print("MemoryLayout<String>.stride=", MemoryLayout<String>.stride)
    print("MemoryLayout<String>.alignment=", MemoryLayout<String>.alignment)
2.1 關聯值的存儲
  • 如果沒有枚舉關聯值時,枚舉變量只占一個字節,這個字節里面的內容就是case的序號。
  • 如果有枚舉關聯值,那么枚舉內存分配 = 各個關聯值類型所占的字節總和 + 1(這1個字節是存放枚舉case序號的)+ 根據內存對齊alignment補齊字節。
  • 內存對齊alignment是關聯值類型中最大的那個。
    證明過程:
    我這里是學習李明杰大師的方法做的,使用他的demo就可以實現:https://github.com/CoderMJLee/Mems
    打開demo --》在main文件頂部寫showEnum() --》運行程序 --》打印枚舉變量地址 --》如圖打開內存面板,輸入這個變量的地址值 --》 即可查看該內存里面的值。
    枚舉關聯值的存儲.jpg
2.2 原始值的存儲

rawValue是一個計算屬性,在編譯時就已經確定了每個枚舉值對應的rawValue值,不需要存儲。證明方法: 可以分析swift文件編譯過程生成的中間文件sil
可以參考文章:Swift進階(六)枚舉和可選類型

2.3 枚舉中方法、計算屬性在內存中什么位置?
    1. 計算屬性也可以認為是方法,方法的本質就是函數, 方法、函數都存放在代碼段,所以計算屬性、成員方法都存放在代碼段。
    1. 靜態變量就是全局變量,存放在內存的數據段。
    1. 靜態方法存放在代碼段。
      證明方法見博客Swift 方法及方法在內存中的位置
三、Swift枚舉應用舉例
    1. 跟OC語言枚舉一樣的情況,比如訂單狀態枚舉。
    1. 應用于將多個相似的方法整合成一個,比如:RxSwift中的信號發送。
// 在OC中是分別有onNext、onComplete、onError三個方法,RxSwift的內部中轉方法只使用一個on
func on(_ event: Event<Element>)
public enum Event<Element> {
    /// Next element is produced.
    case next(Element)
    /// Sequence terminated with an error.
    case error(Swift.Error)
    /// Sequence completed successfully.
    case completed
}
    1. 系統的可選類型也是一個枚舉。可選類型可以賦值為nil,相當于賦值了Optional.none, 原因是遵守了ExpressibleByNilLiteral協議。
    1. 將APP所有的通知名集中到一個枚舉中,枚舉原始值類型聲明為String,這樣在使用直接用點語法找case,而且APP中包含哪些通知也變得一目了然。
    1. 埋點神策事件時使用枚舉關聯值來做,代碼設計感會很不錯。
    1. 網絡請求使用Moya來實現的話,一個請求對應相關聯參數,這個也可以用枚舉關聯值來做。
四、OC中使用Swift枚舉

OC文件中導入#import "項目名-Swift.h"文件后去使用。

'@objc' enum must declare an integer raw type.
枚舉原始值類型為Int的Swift枚舉才允許在OC中使用,并且Swift枚舉前需要加@objc。注意:OC中Integer就是Swift中的Int。

五、Swift中使用OC枚舉

將OC枚舉所在的文件導入到橋接文件中項目名-Bridging-Header.h
Swift中用枚舉類型名 + 點語法就可以了。

OC中定義字符串枚舉:
Apple官方的做法

.h 文件中
typedef NSString *AddressRecType NS_STRING_ENUM;

FOUNDATION_EXPORT AddressRecType const AddressRecTypeHistory;
FOUNDATION_EXPORT AddressRecType const AddressRecTypeCurrentLocation;
FOUNDATION_EXPORT AddressRecType const AddressRecTypeRGeo;

.m 文件中
AddressRecType const AddressRecTypeHistory = @"history";
AddressRecType const AddressRecTypeCurrentLocation = @"curLocation";
AddressRecType const AddressRecTypeRGeo = @"RGeo";

.swift 文件中 --------------
let enum5 = AddressRecType.currentLocation

有些情況使用字符串枚舉更合適,比如:你寫一個Pod私有庫需要提供給Swift新項目中業務方使用,他們使用的方式是需要取到這個枚舉對應的一個字符串類型作為參數去發送請求,這個參數如果由業務方根據枚舉做一層映射的話,這樣業務方麻煩,也怕他們會寫錯。
這個時候可以在OC中定義字符串枚舉后,在Swift中使用該枚舉的rawValue來取得這個字符串就能避免這個問題。

  • Handle unknown values using "@unknown default"的問題
    在Swift中對OC枚舉所有case都處理后,仍然會有警告:
    Switch covers known cases, but 'ToastType' may have additional unknown values. Handle unknown values using "@unknown default"
    就是提示還需要處理未來可能新增加的case. 對于我們枚舉中已經確定不會增加新的case了,OC中可以使用NS_CLOSED_ENUM來定義穩定的枚舉。
typedef NS_CLOSED_ENUM(int, ToastType) {
    ToastTypeNormal,         // 文字
    ToastTypeSucceed,        // 成功
    ToastTypeWarn,           // 警告
    ToastTypeError,          // 錯誤
    ToastTypeLoading       // 加載
};
最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,119評論 6 531
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,382評論 3 415
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,038評論 0 373
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 62,853評論 1 309
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,616評論 6 408
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,112評論 1 323
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,192評論 3 441
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,355評論 0 288
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 48,869評論 1 334
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,727評論 3 354
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 42,928評論 1 369
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,467評論 5 358
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,165評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,570評論 0 26
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 35,813評論 1 282
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,585評論 3 390
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 47,892評論 2 372

推薦閱讀更多精彩內容