iOS-SwiftyJSON個人淺析

一個最簡單的使用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再將IntString下標(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ù)字類型等等等等,不再一一敘述驻啤。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末菲驴,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子骑冗,更是在濱河造成了極大的恐慌赊瞬,老刑警劉巖,帶你破解...
    沈念sama閱讀 217,657評論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件贼涩,死亡現(xiàn)場離奇詭異巧涧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)遥倦,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,889評論 3 394
  • 文/潘曉璐 我一進(jìn)店門谤绳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人袒哥,你說我怎么就攤上這事缩筛。” “怎么了堡称?”我有些...
    開封第一講書人閱讀 164,057評論 0 354
  • 文/不壞的土叔 我叫張陵瞎抛,是天一觀的道長。 經(jīng)常有香客問我却紧,道長桐臊,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,509評論 1 293
  • 正文 為了忘掉前任晓殊,我火速辦了婚禮断凶,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘挺物。我一直安慰自己懒浮,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,562評論 6 392
  • 文/花漫 我一把揭開白布识藤。 她就那樣靜靜地躺著砚著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪痴昧。 梳的紋絲不亂的頭發(fā)上稽穆,一...
    開封第一講書人閱讀 51,443評論 1 302
  • 那天,我揣著相機(jī)與錄音赶撰,去河邊找鬼舌镶。 笑死柱彻,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的餐胀。 我是一名探鬼主播哟楷,決...
    沈念sama閱讀 40,251評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼否灾!你這毒婦竟也來了卖擅?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,129評論 0 276
  • 序言:老撾萬榮一對情侶失蹤墨技,失蹤者是張志新(化名)和其女友劉穎惩阶,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體扣汪,經(jīng)...
    沈念sama閱讀 45,561評論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡断楷,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,779評論 3 335
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了崭别。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片冬筒。...
    茶點(diǎn)故事閱讀 39,902評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖紊遵,靈堂內(nèi)的尸體忽然破棺而出账千,到底是詐尸還是另有隱情侥蒙,我是刑警寧澤暗膜,帶...
    沈念sama閱讀 35,621評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站鞭衩,受9級特大地震影響学搜,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜论衍,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,220評論 3 328
  • 文/蒙蒙 一瑞佩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧坯台,春花似錦炬丸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,838評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至咪啡,卻和暖如春首启,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背撤摸。 一陣腳步聲響...
    開封第一講書人閱讀 32,971評論 1 269
  • 我被黑心中介騙來泰國打工毅桃, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留褒纲,地道東北人。 一個月前我還...
    沈念sama閱讀 48,025評論 2 370
  • 正文 我出身青樓钥飞,卻偏偏與公主長得像莺掠,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子读宙,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,843評論 2 354

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