【iOS開(kāi)發(fā)】使用Codable時(shí)要注意的問(wèn)題

在Swift 4推出Codable之后,我們基本上可以拋棄字典轉(zhuǎn)模型的第三方庫(kù)了儒陨。在我自己的使用過(guò)程中,發(fā)現(xiàn)了一些會(huì)導(dǎo)致無(wú)法解碼JSON的細(xì)節(jié)問(wèn)題笋籽。在此跟大家分享下蹦漠。

一、類型的某個(gè)屬性有默認(rèn)值车海,后臺(tái)返回的JSON沒(méi)有這個(gè)屬性對(duì)應(yīng)的數(shù)據(jù)

正常的Demo

User

假設(shè)我們有一個(gè)User類型笛园,有一個(gè)id屬性,和一個(gè)是否被當(dāng)前用戶關(guān)注的屬性isFollowedByCurrentUser容劳,并實(shí)現(xiàn)了Codable協(xié)議喘沿,代碼如下:

struct User: Codable {
    var id: String
    var isFollowedByCurrentUser: Bool?

    enum CodingKeys: String, CodingKey {
        case id
        case isFollowedByCurrentUser = "followed"
    }
}
解碼

我們的JSON數(shù)據(jù)如下:

let jsonString = """
  {
    "id":"efa41bae-25fa-428b-99c1-6d3c1b178875",
    "followed": true
  }
"""

JSONDecoder進(jìn)行解碼:

let decoder = JSONDecoder()

let data = jsonString.data(using: .utf8)!

do {
    let user = try decoder.decode(User.self, from: data)
    print(user)
} catch {
    print("error: \(error)")
}

毫無(wú)疑問(wèn),上面的代碼是可以解碼成功的竭贩。

失敗的Demo

有些時(shí)候蚜印,后臺(tái)返回的JSON數(shù)據(jù)可能缺少某些字段,假設(shè)缺少了followed留量,那么現(xiàn)在的JSON數(shù)據(jù)為:

let jsonString = """
  {
    "id":"efa41bae-25fa-428b-99c1-6d3c1b178875"
  }
"""

這時(shí)我們用上面的JSONDecoder進(jìn)行解碼窄赋,也是可以解碼成功的,只不過(guò)isFollowedByCurrentUser的值為nil而已楼熄。

現(xiàn)在問(wèn)題來(lái)了忆绰,我們看回User類型。通常我們?cè)谀硞€(gè)類型添加一個(gè)Bool屬性時(shí)可岂,一般會(huì)給他一個(gè)默認(rèn)值false错敢,所以我們會(huì)習(xí)慣的把User寫成:

struct User: Codable {

    var id: String
    var isFollowedByCurrentUser = false

    enum CodingKeys: String, CodingKey {
        case id
        case isFollowedByCurrentUser = "followed"
    }
}

這時(shí)如果我們?cè)儆?code>JSONDecoder把缺少followed字段的JSON數(shù)據(jù)轉(zhuǎn)成User的話,是無(wú)法轉(zhuǎn)成功的缕粹,錯(cuò)誤如下:

error: keyNotFound(CodingKeys(stringValue: "followed", intValue: nil), Swift.DecodingError.Context(codingPath: [], debugDescription: "No value associated with key CodingKeys(stringValue: \"followed\", intValue: nil) (\"followed\").", underlyingError: nil))

JSONDecoder在JSON數(shù)據(jù)中無(wú)法找到followed對(duì)應(yīng)的值稚茅。

解決辦法

我們無(wú)法保證服務(wù)器總是返回完整的數(shù)據(jù),所以只能從我們客戶端去解決問(wèn)題平斩。

1. 把類型的所有屬性都定義為Optional類型

這是最簡(jiǎn)單方便的方法亚享。這樣解碼的時(shí)候,JSONDecoder發(fā)現(xiàn)JSON沒(méi)有對(duì)應(yīng)的數(shù)據(jù)绘面,就自動(dòng)把這個(gè)屬性設(shè)置為nil欺税。

2. 實(shí)現(xiàn)Decodable的初始化函數(shù)侈沪,并使用decodeIfPresent來(lái)解碼

正常情況下,我們定義了CodingKeys之后晚凿,不需要手動(dòng)實(shí)現(xiàn)init(from decoder: Decoder) throws這個(gè)初始化函數(shù)的亭罪,JSONDecoder就可以正常解碼。但是我們把isFollowedByCurrentUser定義成一個(gè)非可選類型晃虫,我們必須實(shí)現(xiàn)這個(gè)初始化函數(shù)皆撩,才能正常解碼:

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    id = try container.decode(String.self, forKey: .id)
    isFollowedByCurrentUser = try container.decodeIfPresent(Bool.self, forKey: .isFollowedByCurrentUser) ?? false
}

歡迎加入我管理的Swift開(kāi)發(fā)群:536353151扣墩。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末哲银,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子呻惕,更是在濱河造成了極大的恐慌荆责,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,126評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件亚脆,死亡現(xiàn)場(chǎng)離奇詭異做院,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)濒持,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,254評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門键耕,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人柑营,你說(shuō)我怎么就攤上這事屈雄。” “怎么了官套?”我有些...
    開(kāi)封第一講書人閱讀 152,445評(píng)論 0 341
  • 文/不壞的土叔 我叫張陵酒奶,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我奶赔,道長(zhǎng)惋嚎,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,185評(píng)論 1 278
  • 正文 為了忘掉前任站刑,我火速辦了婚禮另伍,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘绞旅。我一直安慰自己摆尝,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,178評(píng)論 5 371
  • 文/花漫 我一把揭開(kāi)白布玻靡。 她就那樣靜靜地躺著结榄,像睡著了一般。 火紅的嫁衣襯著肌膚如雪囤捻。 梳的紋絲不亂的頭發(fā)上臼朗,一...
    開(kāi)封第一講書人閱讀 48,970評(píng)論 1 284
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼视哑。 笑死绣否,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的挡毅。 我是一名探鬼主播蒜撮,決...
    沈念sama閱讀 38,276評(píng)論 3 399
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼跪呈!你這毒婦竟也來(lái)了段磨?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 36,927評(píng)論 0 259
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤耗绿,失蹤者是張志新(化名)和其女友劉穎苹支,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體误阻,經(jīng)...
    沈念sama閱讀 43,400評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡债蜜,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 35,883評(píng)論 2 323
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了究反。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片寻定。...
    茶點(diǎn)故事閱讀 37,997評(píng)論 1 333
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖精耐,靈堂內(nèi)的尸體忽然破棺而出狼速,到底是詐尸還是另有隱情,我是刑警寧澤黍氮,帶...
    沈念sama閱讀 33,646評(píng)論 4 322
  • 正文 年R本政府宣布唐含,位于F島的核電站,受9級(jí)特大地震影響沫浆,放射性物質(zhì)發(fā)生泄漏捷枯。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,213評(píng)論 3 307
  • 文/蒙蒙 一专执、第九天 我趴在偏房一處隱蔽的房頂上張望淮捆。 院中可真熱鬧,春花似錦本股、人聲如沸攀痊。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,204評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)苟径。三九已至,卻和暖如春躬审,著一層夾襖步出監(jiān)牢的瞬間棘街,已是汗流浹背蟆盐。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,423評(píng)論 1 260
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留遭殉,地道東北人石挂。 一個(gè)月前我還...
    沈念sama閱讀 45,423評(píng)論 2 352
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像险污,于是被迫代替她去往敵國(guó)和親痹愚。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,722評(píng)論 2 345

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