javascript
SwiftyJSON 对网络请求来的数据进行解析或者转为modul
JSON是移動(dòng)端開(kāi)發(fā)常用的應(yīng)用層數(shù)據(jù)交換協(xié)議。最常見(jiàn)的場(chǎng)景便是,客戶端向服務(wù)端發(fā)起網(wǎng)絡(luò)請(qǐng)求,服務(wù)端返回JSON文本,然后客戶端解析這個(gè)JSON文本,再把對(duì)應(yīng)數(shù)據(jù)展現(xiàn)到頁(yè)面上。
但在編程的時(shí)候,處理JSON是一件麻煩事。在不引入任何輪子的情況下,我們通常需要先把JSON轉(zhuǎn)為Dictionary,然后還要記住每個(gè)數(shù)據(jù)對(duì)應(yīng)的Key,用這個(gè)Key在Dictionary中取出對(duì)應(yīng)的Value來(lái)使用。這個(gè)過(guò)程我們會(huì)犯各種錯(cuò)誤:
* Key拼寫(xiě)錯(cuò)了
* 路徑寫(xiě)錯(cuò)了
* 類(lèi)型搞錯(cuò)了
* 沒(méi)拿到值懵逼了
* 某一天和服務(wù)端約定的某個(gè)字段變更了,沒(méi)能更新所有用到它的地方
* ...
為了解決這些問(wèn)題,很多處理JSON的開(kāi)源庫(kù)應(yīng)運(yùn)而生。在Swift中,這些開(kāi)源庫(kù)主要朝著兩個(gè)方向努力:
1. 保持JSON語(yǔ)義,直接解析JSON,但通過(guò)封裝使調(diào)用方式更優(yōu)雅、更安全
2. 預(yù)定義Model類(lèi),將JSON反序列化為類(lèi)實(shí)例,再使用這些實(shí)例
對(duì)于1,使用最廣、評(píng)價(jià)最好的庫(kù)非 SwiftyJSON 莫屬,它很能代表這個(gè)方向的核心。它本質(zhì)上仍然是根據(jù)JSON結(jié)構(gòu)去取值,使用起來(lái)順手、清晰。但也正因如此,這種做法沒(méi)能妥善解決上述的幾個(gè)問(wèn)題,因?yàn)镵ey、路徑、類(lèi)型仍然需要開(kāi)發(fā)者去指定;
對(duì)于2,我個(gè)人覺(jué)得這是更合理的方式。由于Model類(lèi)的存在,JSON的解析和使用都受到了定義的約束,只要客戶端和服務(wù)端約定好了這個(gè)Model類(lèi),客戶端定義后,在業(yè)務(wù)中使用數(shù)據(jù)時(shí)就可以享受到語(yǔ)法檢查、屬性預(yù)覽、屬性補(bǔ)全等好處,而且一旦數(shù)據(jù)定義變更,編譯器會(huì)強(qiáng)制所有用到的地方都改過(guò)來(lái)才能編譯通過(guò),非常安全。這個(gè)方向上,開(kāi)源庫(kù)們做的工作,主要就是把JSON文本反序列化到Model類(lèi)上了。這一類(lèi)JSON庫(kù)有 ObjectMapper、JSONNeverDie、HandyJSON 等。
今天我們先來(lái)看看SwiftyJSON的用法。
通常我們拿到數(shù)據(jù)會(huì)進(jìn)行非常麻煩的optinonal(可選類(lèi)型)進(jìn)行拆包(Wrapping )操作,
SwiftyJson內(nèi)部會(huì)自動(dòng)對(duì)optional進(jìn)行拆包,大大簡(jiǎn)化了代碼,解析非常方便,拿到的json數(shù)據(jù)data直接扔進(jìn)去
???????
//轉(zhuǎn)成JSON對(duì)象
let jsonData = JSON.init(data)
不管需要什么數(shù)據(jù)只要通過(guò)對(duì)jsonData進(jìn)行路徑讀取
例如:
值得一提的是,不需要考慮服務(wù)器給我們返回的是什么類(lèi)型,比如去請(qǐng)求一個(gè)房屋的棟數(shù)"build_num": 588我們想要獲得Int類(lèi)型或者String類(lèi)型都可以
let room_num1 = jsonData[0]["build_num"].stringValue let room_num2 = jsonData[0]["build_num"].intValue // room_num1 = 588 ? String類(lèi)型 // room_num2 = 588 ? Int類(lèi)型這樣通過(guò).stringValue.intValue就可以獲得不可選值類(lèi)型,如果沒(méi)有獲取到數(shù)據(jù)的話就會(huì)返回一個(gè)默認(rèn)值即.stringValue獲得空字符串"",.intValue得到0,.arrayValue獲得空數(shù)組[],我們就不用判斷拆包了。當(dāng)然某些場(chǎng)景可能需要你得到可選值類(lèi)型并自己判斷是否存在,那么我們可以通過(guò).string .int .bool .float .array .dictionary等等方法獲取,例如:
???????
//String
if let build_name = jsonData[0]["build_name"].string {
? ? print(build_name)
} else {
? ? //打印錯(cuò)誤信息
? ? print(jsonData[0]["build_name"])
}
解析數(shù)據(jù)是真的非常簡(jiǎn)單。詳細(xì)使用可以看看SwiftyJSON的使用詳解(附樣例)
或者移步GitHub-SwiftyJson
但是對(duì)于項(xiàng)目而言我們需要對(duì)數(shù)據(jù)進(jìn)行轉(zhuǎn)換為模型,僅僅是對(duì)data進(jìn)行JSON讀取是遠(yuǎn)遠(yuǎn)不夠的,想想,如果遇到許多地方都用到了build_name值,但是當(dāng)服務(wù)器給我們返回的字段名字改了,我們改項(xiàng)目時(shí)就會(huì)顯得麻煩,甚至造成改不完全,所以我們隊(duì)數(shù)據(jù)封裝一下轉(zhuǎn)為模型,這樣修改時(shí)只用改一個(gè)地方就是model的賦值就好了。
那我的方法是:
???????
//這是模擬數(shù)據(jù)
let baseInfo: [String : Any] = ["build_name":"置信·原墅",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "build_address":"學(xué)院中路與金橋路交匯處東北側(cè)",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "build_num": 12,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "room_num": 588,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "area_address":"浙江省溫州市鹿城區(qū)五馬街道"]
創(chuàng)建struct模型,當(dāng)然Class也可以,但是如果不需要繼承也不復(fù)雜推薦struct(-。-不多解釋了)
并寫(xiě)好創(chuàng)建方法
???????
import SwiftyJSON
?
struct BuildBaseInfoModel {
? ? var build_name: String?
? ? var build_address: String?
? ? var build_num: String?
? ? var room_num: String?
? ? var area_address: String?
? ??
? ? init(jsonData: JSON) {
? ? ? ? build_name ? ?= jsonData["build_name"].stringValue
? ? ? ? build_address = jsonData["build_address"].stringValue
? ? ? ? area_address ?= jsonData["area_address"].stringValue
? ? ? ? room_num ? ? ?= jsonData["room_num"].stringValue
? ? ? ? build_num ? ? = jsonData["build_num"].stringValue
? ? }
}
調(diào)用:
???????
let jsonData = JSON(baseInfo)
let model = BuildBaseInfoModel.init(jsonData: jsonData)
// 會(huì)得到創(chuàng)建好的 BuildBaseInfoModel類(lèi)型的 對(duì)象model
// 也可以這樣寫(xiě)
let model = BuildBaseInfoModel(jsonData: jsonData)
當(dāng)然這只是普通的模型,經(jīng)常會(huì)遇到復(fù)雜模型,例如:
???????
// 面積中89是Int, 109和129是String
let baseInfo: [String : Any] = ["build_name":"置信·原墅",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "build_address":"學(xué)院中路與金橋路交匯處東北側(cè)",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "area_address":"浙江省溫州市鹿城區(qū)五馬街道",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "area":[89,"109","129"],
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "detail_address":["province":"浙江省",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "city":"溫州市",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "district":"鹿城區(qū)",
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "street":"五馬街道"],
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "build_num": 12,
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? "room_num": 588]
這時(shí)候模型就應(yīng)該有兩個(gè)
???????
struct BuildBaseInfoModel {
? ??
? ? var build_name: String?
? ? var build_address: String?
? ? var build_num: String?
? ? var room_num: String?
? ? var area_address: String?
? ? var detail_address: DetailAddressModel
? ? var area:[Any]?
? ? // 這里面積area中就不能再用arrayValue獲取了,因?yàn)閍rrayValue獲取的為JSON類(lèi)型,我們需要轉(zhuǎn)為我們需要的對(duì)象
? ? init(jsonData: JSON) {
? ? ? ? build_name ? ?= jsonData["build_name"].stringValue
? ? ? ? build_address = jsonData["build_address"].stringValue
? ? ? ? area_address ?= jsonData["area_address"].stringValue
? ? ? ? room_num ? ? ?= jsonData["room_num"].stringValue
? ? ? ? build_num ? ? = jsonData["build_num"].stringValue
? ? ? ? area ? ? ? ? ?= jsonData["area"].arrayObject
? ? ? ? detail_address = DetailAddressModel(jsonData: jsonData["detail_address"])
? ? }
}
struct DetailAddressModel {
? ? var province: String?
? ? var city: String?
? ? var district: String?
? ? var street: String?
? ??
? ? init(jsonData: JSON) {
? ? ? ? province = jsonData["province"].stringValue
? ? ? ? city = jsonData["city"].stringValue
? ? ? ? district = jsonData["district"].stringValue
? ? ? ? street = jsonData["street"].stringValue
? ? }
? ??
}
?
總結(jié)
以上是生活随笔為你收集整理的SwiftyJSON 对网络请求来的数据进行解析或者转为modul的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。