使用OptionSet優(yōu)化Codable的enmu解析

在swift 4.0之后旭绒,官方提供了Codable來解析json為對應(yīng)的Model,這比一些第三方框架簡單優(yōu)雅了許多,并且由于它是官方的袋倔,穩(wěn)定性也有了很好的保障扇售。

具體如何使用Codable來映射解析json并不是本文的重點巷懈,相信大家也都知道如何使用欧引,本文主要討論在解析枚舉數(shù)據(jù)的時候遇到的問題婚苹,特別是可變枚舉的情況廓译。

常規(guī)enum

對于后端接口數(shù)據(jù)中有一些確定值范圍的字段,比如性別這種,我們會使用枚舉來解析這個字段。假如我們有如下這樣的一個json數(shù)據(jù),下文增加修改字段都是在該json的基礎(chǔ)上進(jìn)行的:

 {
     "name": "rocky",
     "sex": "male"
 }

我們和后端約定sex字段只能傳遞字符串male凄鼻、female(當(dāng)然峭范,為了減少數(shù)據(jù)量,也會使用Int類型來表示對應(yīng)的值)褪尝,因此我們可以很容易的寫出來對應(yīng)的Person模型:

struct Person: Codable {
    let name: String
    let sex: Sex

    enum Sex: String, Codable {
        case male
        case female
    }
}

借助于JSONDecoder我們可以將json轉(zhuǎn)化為對應(yīng)的Person:

let person_json_data = JSONSerialization.data(withJSONObject: person_json, options: [.fragmentsAllowed])
let person = JSONDecoder().decode(Person.self, from: person_json_data)

但是在這個過程中佳吞,如果后端增加了一個sex字段的值:unknown鹊汛,而且我們解析json的代碼已經(jīng)發(fā)版上線了,只要后端修改過后的接口一上線,就會解析失敗蛔添。

除了后端對該值做版本控制之外,我們別無他法,雖然版本控制修補丁還可以首量,如果涉及到大面積的字段有變動柄延,那就會割裂后端同學(xué)的代碼邏輯。

如果一開始不使用枚舉,而是直接使用String伪嫁、Int來保存數(shù)據(jù)就不會有這樣的問題了,既然我們這里討論的是Codable下對enum的解析提鸟,那么這種case就不用考慮了。

使用OptionSet

上面的情況一般的發(fā)生主要在于業(yè)務(wù)變動,業(yè)務(wù)變動是無法預(yù)期的北发,但是我們可以使用OptionSet來提前預(yù)防這種情況恶耽。

OptionSet一般用來可以組合的枚舉,通過操作來達(dá)到對枚舉的組合拆祈,比如UIKit中設(shè)置圓角的UIRectCorner就是他的一個應(yīng)用:

struct UIRectCorner : OptionSet {
    
    static var topLeft: UIRectCorner { get }
    static var topRight: UIRectCorner { get }
    static var bottomLeft: UIRectCorner { get }
    static var bottomRight: UIRectCorner { get }
    static var allCorners: UIRectCorner { get }
}

雖然看起來不是枚舉溉苛,但是卻可以達(dá)到枚舉的效果,我們可以使用OptionSet來實現(xiàn)一個具有兼容性的枚舉彰檬。

假如現(xiàn)在json中新增一個level的字段挚币,這個字段我們使用Int類存儲:

{
   ...
   "level": 2,
   ...
}

對應(yīng)的,Person中也需要新增一個Level的struct來解析這個字段:

struct Person: Codable {
    
   ...

   let level: Level

   struct Level: Codable, OptionSet {

       typealias RawValue = Int
       var rawValue: Int
       init(rawValue: Int) {
           self.rawValue = rawValue
       }

       static let low = Level(rawValue: 1 << 0) // 1

       static let middle = Level(rawValue: 2 << 0) // 2

       static let high = Level(rawValue: 3 << 0) // 3
   }
}

這個時候润努,通過JSONDecoder我們解析得到的level為middle裁着。

如果接口中新增了level相關(guān)的字段,比如:higher扔罪,值為4敞咧,使用以前的代碼解析出來的level.rawValue就為4测砂,而不是已經(jīng)設(shè)置好的靜態(tài)對象纵东,最主要的是不會解析失敗。

使用OptionSet之后子檀,依然可以使用if-else镊掖、switch來判斷具體的case乃戈,以switch為例:

 switch person.level {
    case .low:
        print("level low \(person.level.rawValue)")
    case .middle:
        print("level middle \(person.level.rawValue)")
    case .high:
        print("level high \(person.level.rawValue)")
    default:
        print("level unknow \(person.level.rawValue)")
}

既兼顧了enum的特性又具備了可拓展的特點。

問題

雖然使用OptionSet之后我們的數(shù)據(jù)解析代碼邏輯更健壯了亩进,同時也會帶來一些問題症虑。

首先就是代碼量增加了很多。針對這一點归薛,我認(rèn)為是值得的谍憔。特別是業(yè)務(wù)變動頻繁帶來的線上hot-fix等高成本的操作,多寫這一部分代碼顯得沒有那么重主籍,另外可以在業(yè)務(wù)穩(wěn)定之后习贫,將struct替換為enum即可,幾乎是無縫切換千元。

另外一個問題就是switch-case這樣的判斷邏輯上苫昌。我們知道enum中如果每個case都進(jìn)行了區(qū)分,再新增一個case幸海,編譯器就會直接報錯祟身,提示我們有新增的case,記得在switch中進(jìn)行區(qū)分涕烧。

而使用OptionSet之后月而,新增一個case,編譯器并不會為我們進(jìn)行提示议纯,這就需要我們按照業(yè)務(wù)來主動添加了父款,這也無可厚非,畢竟有新業(yè)務(wù)變動了瞻凤,肯定是要涉及到的地方都要修改了憨攒。

使用OptionSet實現(xiàn)enum的邏輯所帶來的問題目前看來都是可以接受的,OptionSet也只是一種用于預(yù)防Codable解析失敗的方式阀参,具體業(yè)務(wù)中最好還是使用enum來實現(xiàn)枚舉功能肝集。

當(dāng)然,如果業(yè)務(wù)變動很頻繁蛛壳,還是推薦使用OptionSet來提升代碼的健壯性的杏瞻。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市衙荐,隨后出現(xiàn)的幾起案子捞挥,更是在濱河造成了極大的恐慌,老刑警劉巖忧吟,帶你破解...
    沈念sama閱讀 216,470評論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件砌函,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機讹俊,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評論 3 392
  • 文/潘曉璐 我一進(jìn)店門垦沉,熙熙樓的掌柜王于貴愁眉苦臉地迎上來枕稀,“玉大人昙沦,你說我怎么就攤上這事∩蟹眨” “怎么了耳奕?”我有些...
    開封第一講書人閱讀 162,577評論 0 353
  • 文/不壞的土叔 我叫張陵绑青,是天一觀的道長。 經(jīng)常有香客問我屋群,道長,這世上最難降的妖魔是什么坏挠? 我笑而不...
    開封第一講書人閱讀 58,176評論 1 292
  • 正文 為了忘掉前任芍躏,我火速辦了婚禮,結(jié)果婚禮上降狠,老公的妹妹穿的比我還像新娘对竣。我一直安慰自己,他們只是感情好榜配,可當(dāng)我...
    茶點故事閱讀 67,189評論 6 388
  • 文/花漫 我一把揭開白布否纬。 她就那樣靜靜地躺著,像睡著了一般蛋褥。 火紅的嫁衣襯著肌膚如雪临燃。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,155評論 1 299
  • 那天烙心,我揣著相機與錄音膜廊,去河邊找鬼。 笑死淫茵,一個胖子當(dāng)著我的面吹牛爪瓜,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播匙瘪,決...
    沈念sama閱讀 40,041評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼铆铆,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了丹喻?” 一聲冷哼從身側(cè)響起薄货,我...
    開封第一講書人閱讀 38,903評論 0 274
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎驻啤,沒想到半個月后菲驴,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評論 1 310
  • 正文 獨居荒郊野嶺守林人離奇死亡骑冗,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,539評論 2 332
  • 正文 我和宋清朗相戀三年赊瞬,在試婚紗的時候發(fā)現(xiàn)自己被綠了先煎。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,703評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡巧涧,死狀恐怖薯蝎,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情谤绳,我是刑警寧澤占锯,帶...
    沈念sama閱讀 35,417評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站缩筛,受9級特大地震影響消略,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜瞎抛,卻給世界環(huán)境...
    茶點故事閱讀 41,013評論 3 325
  • 文/蒙蒙 一艺演、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧桐臊,春花似錦胎撤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,664評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至认烁,卻和暖如春肿男,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背砚著。 一陣腳步聲響...
    開封第一講書人閱讀 32,818評論 1 269
  • 我被黑心中介騙來泰國打工次伶, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人稽穆。 一個月前我還...
    沈念sama閱讀 47,711評論 2 368
  • 正文 我出身青樓冠王,卻偏偏與公主長得像,于是被迫代替她去往敵國和親舌镶。 傳聞我的和親對象是個殘疾皇子柱彻,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,601評論 2 353

推薦閱讀更多精彩內(nèi)容