一個最簡單的使用SwiftyJSON的示例:
let a = JSON.init(parseJSON: "{\"name\":\"dante\",\"age\":\"18\"}")
SwiftyJSON
提供了多種初始化接口峦筒,根據(jù)不同類型的數(shù)據(jù)在內(nèi)部進(jìn)行不同的轉(zhuǎn)換最終都?xì)w納到統(tǒng)一的接口完成初始化:
fileprivate init(jsonObject: Any) {
self.object = jsonObject
}
但在此之前忧饭,多種多樣或符合JSON標(biāo)準(zhǔn)或不符合的數(shù)據(jù)都要經(jīng)過中轉(zhuǎn)站:
public init(_ object: Any) {
switch object {
case let object as [JSON] where object.count > 0:
self.init(array: object)
case let object as [String: JSON] where object.count > 0:
self.init(dictionary: object)
case let object as Data:
self.init(data: object)
default:
self.init(jsonObject: object)
}
}
通過這個函數(shù)渣刷,SwiftyJSON
將數(shù)據(jù)轉(zhuǎn)換為需要的Any
對象古拴,例如,當(dāng)我們將一個JSON
類型的數(shù)組對一個JSON
進(jìn)行初始化(雖然我不知道在何種狀況下能達(dá)成條件):
let a = JSON.init(parseJSON: "{\"name\":\"dante\",\"age\":\"18\"}")
let b = JSON.init(parseJSON: "{\"name\":\"dante\",\"age\":\"18\"}")
let c = JSON.init(parseJSON: "{\"name\":\"dante\",\"age\":\"18\"}")
let d = JSON.init(parseJSON: "{\"name\":\"dante\",\"age\":\"18\"}")
let e = JSON.init(parseJSON: "{\"name\":\"dante\",\"age\":\"18\"}")
let arr = [a,b,c,d,e]
let output = JSON.init(arr)
SwiftyJSON
會通過遍歷JSON
數(shù)組以獲取代表真實(shí)數(shù)據(jù)的JSON
實(shí)例對象的object屬性赂乐,object屬性根據(jù)數(shù)據(jù)真實(shí)類型獲取對應(yīng)類型的數(shù)據(jù)屋厘,最終返還給output
涕烧,生成新JSON
對象,這一步的作用是避免多層嵌套JSON的產(chǎn)生導(dǎo)致的結(jié)構(gòu)趨向復(fù)雜汗洒。
[String: JSON]
也是同理便锨。
最后解取,我們獲得且僅獲得一個可能包含任意數(shù)據(jù)類型但表現(xiàn)為數(shù)據(jù)安全的object
對象漱受。
set {
_error = nil
switch newValue {
case let number as NSNumber:
if number.isBool {
_type = .bool
self.rawBool = number.boolValue
} else {
_type = .number
self.rawNumber = number
}
case let string as String:
_type = .string
self.rawString = string
case _ as NSNull:
_type = .null
case _ as [JSON]:
_type = .array
case nil:
_type = .null
case let array as [Any]:
_type = .array
self.rawArray = array
case let dictionary as [String : Any]:
_type = .dictionary
self.rawDictionary = dictionary
default:
_type = .unknown
_error = NSError(domain: ErrorDomain, code: ErrorUnsupportedType, userInfo: [NSLocalizedDescriptionKey: "It is a unsupported type"])
}
}
當(dāng)object
屬性被賦值時伶唯,逐步判斷object的類型,并賦值枚舉世杀,同時向相應(yīng)的代表真實(shí)數(shù)據(jù)的屬性填值阀参。
于此,SwiftyJSON
完成了對數(shù)據(jù)的安全存儲瞻坝,保證即使數(shù)據(jù)錯誤也不會導(dǎo)致崩潰的后果蛛壳,這很重要,因?yàn)槊看瓮ㄟ^json[0]["user"]["name"]
諸如這樣的方式去獲取被SwiftyJSON
存儲的數(shù)據(jù)時都是在重復(fù)上述的初始化方式。
fileprivate subscript(index index: Int) -> JSON {
get {
if self.type != .array {
var r = JSON.null
r._error = self._error ?? NSError(domain: ErrorDomain, code: ErrorWrongType, userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] failure, It is not an array"])
return r
} else if index >= 0 && index < self.rawArray.count {
return JSON(self.rawArray[index])
} else {
var r = JSON.null
r._error = NSError(domain: ErrorDomain, code:ErrorIndexOutOfBounds , userInfo: [NSLocalizedDescriptionKey: "Array[\(index)] is out of bounds"])
return r
}
}
set {
if self.type == .array {
if self.rawArray.count > index && newValue.error == nil {
self.rawArray[index] = newValue.object
}
}
}
}
SwiftyJSON
實(shí)現(xiàn)了復(fù)數(shù)的下標(biāo)函數(shù)分別對數(shù)字下標(biāo)衙荐、字符串下標(biāo)捞挥、數(shù)字及字符串多參數(shù)下標(biāo)以及數(shù)字與字符串?dāng)?shù)組下標(biāo)等形式的數(shù)據(jù)獲取與請求方式。
如上面的源碼忧吟,當(dāng)調(diào)用數(shù)字下標(biāo)時砌函,首先判斷調(diào)用者在初始化時賦予的類型是否是數(shù)組,若是則取出對應(yīng)的真實(shí)數(shù)據(jù)數(shù)組中的真實(shí)數(shù)據(jù)溜族,并使用新的JSON
容器包裹返回讹俊,通過JSON
初始化函數(shù)避免崩潰性錯誤以及通過這種類鏈?zhǔn)秸Z法方便操作。
字符串下標(biāo)亦是同理斩祭。
有趣的地方在于數(shù)字下標(biāo)與字符串下標(biāo)混合使用劣像,就像這樣:
let name = json[1,"list",2,"name"].string
跟這樣:
let name = json[[1,"list",2,"name"]].string
SwiftyJSON
聲明了一個JSONSubscriptType
協(xié)議乡话,協(xié)議僅包含一個名為JSONKey
的屬性摧玫,該屬性為一個枚舉:
public enum JSONKey
{
case index(Int)
case key(String)
}
然后,通過擴(kuò)展分別實(shí)現(xiàn)了Int
類型與String
類型的擴(kuò)展绑青,使其遵循協(xié)議:
extension Int: JSONSubscriptType {
public var jsonKey:JSONKey {
return JSONKey.index(self)
}
}
extension String: JSONSubscriptType {
public var jsonKey:JSONKey {
return JSONKey.key(self)
}
}
當(dāng)let name = json[1,"list",2,"name"]
被調(diào)用時诬像,其被作為一組參數(shù)傳入下標(biāo)函數(shù),接著闸婴,首先忽略其過程坏挠,SwiftyJSON
需要的結(jié)果是根據(jù)下標(biāo)數(shù)組的順序拆解最開始的JSON
容器,每一個下標(biāo)做出新的JSON
容器邪乍,然后從這個JSON
中取出真實(shí)數(shù)據(jù)降狠,再用新的JSON
容器包裹,直至遍歷完整個下標(biāo)數(shù)組庇楞。
在獲得數(shù)組后榜配,在暫時不以SwiftyJSON
所寫的代碼為最優(yōu)解時,我們其實(shí)有多種方式可以實(shí)現(xiàn)這個目的吕晌,比如將混合數(shù)組作為[Any]
進(jìn)行遍歷蛋褥,根據(jù)元素類型進(jìn)行強(qiáng)轉(zhuǎn)再調(diào)用JSON
的下標(biāo)函數(shù),這樣也可以達(dá)到相同的目的睛驳。
而SwiftJSON
則是以reduce
函數(shù)來應(yīng)對:
//path: [JSONSubscriptType]
path.reduce(self) { $0[sub: $1] }
通過reduce
函數(shù)的性質(zhì)烙心,將JSON
容器自身作為初始值不斷地根據(jù)下標(biāo)獲取新容器。
在sub
下標(biāo)函數(shù)中通過JSONKey
再將Int
或String
下標(biāo)發(fā)給對應(yīng)的下標(biāo)函數(shù)乏沸。
switch sub.jsonKey {
case .index(let index):
return self[index: index]
case .key(let key): return self[key: key]
}
另外淫茵,SwiftyJSON
也實(shí)現(xiàn)了循環(huán)字典及循環(huán)數(shù)組的功能。
for (key: String, subJson: JSON) in json {
//Do something you want
}
for (index: String, subJson: JSON) in json {
//Do something you want
}
通過聲明Collection
協(xié)議并實(shí)現(xiàn)迭代器相關(guān)函數(shù)蹬跃,根據(jù)初始化時賦予的type
屬性判斷容器中的真實(shí)數(shù)據(jù)是否為字典或者數(shù)組中的一種痘昌,調(diào)用其真實(shí)數(shù)據(jù)的迭代器函數(shù)。
public subscript (position: Index) -> (String, JSON)
{
switch position
{
case .array(let idx):
return (String(idx), JSON(self.rawArray[idx]))
case .dictionary(let idx):
let (key, value) = self.rawDictionary[idx]
return (key, JSON(value))
default:
return ("", JSON.null)
}
}
由此完成了SwiftyJSON
的絕大多數(shù)功能,剩下的七百多行代碼都是對導(dǎo)出真實(shí)數(shù)據(jù)的擴(kuò)展辆苔,例如將NSNumber
類型轉(zhuǎn)化為Double
類型導(dǎo)出算灸,布爾值類型導(dǎo)出成數(shù)字類型等等等等,不再一一敘述驻啤。