javascript
SwiftyJSON源码分析
SwiftyJSON是iOS Swift語言JSON解析的三方庫,主要是基于對iOS原生JSONSerialization類的封裝, 最新的版本是3.4.1,它只有一個swift文件。?
json庫和http庫是哥倆分不開的, Swift語言的http交互可以用Alamofire;還有個Alamofire-SwiftyJSON, 看名字就知道它是使用在Alamofire庫里的JSON解析, 但它依然不支持json和model轉換(感覺比Java的fastjson和Gson庫low了幾條街,Xcode也不支持類似于Android Studio的GsonFormat插件。。。)。
我覺得做項目時應該用不到SwiftyJSON, 因為它不支持json和Model的互轉, 阿里巴巴的HandyJson更貼近于實戰。
分析SwiftyJSON代碼主要是為了學習Swift語言的語法和技巧。 下面先總結一下有用的語法:
1、支持的數據類型, 使用枚舉定義(考慮一下各自的rawValue是多少?):?
case number
case string
case bool
case array
case dictionary
case null
case unknown
}
2、SwiftyJSON暴露出的JSON是結構體,考慮一下為什么不是類? 因為結構體是值拷貝, 即傳參時會新創建一份拷貝。
// MARK: - JSON Basepublic struct JSON {
...
}
3、泛型的用法, 其中Comparable是協議類型, 在Java里稱作接口類。
public enum Index<T: Any>: Comparable 這條語句的意思是泛型T繼承于Any, 可以是任何數據類型。等價于 public enum Index<T>: Comparable 將Any改成AnyObject會怎樣? public enum Index<T: AnyObject>: Comparable 區別是AnyObject必須是類, 即枚舉使用的泛型T數據類型必須是類。調用方法: public typealias JSONIndex = Index<JSON>
public typealias JSONRawIndex = Index<Any>
4、 Dictionary的聲明和構造語法, 注意等號右邊是實例化; 還有N次循環的實現。
var data: [String: JSON] = [:](0...100000).forEach { n in //循環100001次,n等于[0,100000]
data["(n)"] = JSON([
"name": "item(n)",
"id": n
])
} 分析: (0...100000)的意思是創建一個Array實例,值是從0到100000, forEach是Array的實例方法。 $0和$1是第一個參數、第二個參數, 用在[String:JSON]里$0是String,$1是JSON。
上面的循環還可以這樣寫, 還有個Swift特性就是數字支持下劃線分隔, 100000等價于100_000, 可讀性更好。
for n in 0...100_000 {.... //n的值是從0到100000, 循環100001次
} 如果循環里用不到當前次數,可以用下劃線代替。 for _ in 0...100_000 {
...
}
5、 5種訪問權限 open>public>internal>fileprivate>private, 同比Java的public>protected>private。 extension和subscript的用法都是基本使用方式,不多說。
6、函數參數的默認值, 規則是從后面的參數開始可以設置默認值, 語法是等號和值。 例如下面函數有3個參數, 第2和3個參數都有默認值,在調用時只寫第一個參數也可以。 假如第2個參數有默認值,第3個參數沒有默認值是否可以呢? 答案是No, 如果當前參數有默認值,那么后面的參數必須有默認值。
public init(data: Data, options opt: JSONSerialization.ReadingOptions = .allowFragments, error: NSErrorPointer = nil) 調用:let json = JSON(data:self.testData) //第2個參數是默認值.allowFragments,第3個參數是nil。下面說說JSON解析的實現:
func testInitPerformance() {
self.measure() {
for _ in 1...100 {
print("begin")
print(String(data: self.testData, encoding: String.Encoding.utf8)!)
let json = JSON(data:self.testData)
print("resutl: (json[0]["text"])")
XCTAssertTrue(json != JSON.null)
}
}
}
SwiftyJSON源碼結構如下圖所示:
屏幕快照 2017-01-14 下午3.53.08.png
以testInitPerformance函數為例說明時序:
1、 let json = JSON(data: self.testData)會先執行哪行代碼?
如果你說就是執行了上面提到的init構造函數, 那你就錯了。
跟其它語言類似,如果結構體/類/枚舉有成員變量時, 首先按照代碼次序實例化成員變量; 然后才是構造函數; 這也是lazy關鍵字(即懶加載)存在的意義!
執行的第一條語句.png
2、因為SwiftyJSON是對JSONSerialization類的封裝,對于純文本數據JSON結構體肯定要執行JSONSerialization的方法。
反序列號.png
3、 執行self.init(jsonObject: object)會進入下面的函數, 看起來只有一句話, 但并不是這么簡單哦!
fileprivate init(jsonObject: Any) {self.object = jsonObject //會執行object的set方法(觀察者模式)
}
賦值操作執行了object變量的set方法, 作用是判斷數據類型。
public var object: Any {
get {
... //省略
}
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"])
}
}
JSON對象構造過程到此結束!
下面看看是如何取值的, 以SwiftyJSON比較屌的特性多維取值為例:print("resutl: (json[0]["text"])")
PS: 看到方框應該想到下標語法,對應subcript關鍵字(跟數組取值語法類似)。
1、 SwiftyJSON的官方結束里有這么一句let name = json[1]["list"][2]["name"].string, 參數可以任意長度。 那么函數該怎么聲明參數呢? Swift使用了跟Java類似的...
若干個參數.png
2、因為原始數據是嵌套json格式,根據下標參數類型, 代碼會執行到JSON(o), 在這里是遞歸調用。
字符串.png
就分析這么多了, 如果想了解更多應該分析一下HandyJSON源碼。
總結
以上是生活随笔為你收集整理的SwiftyJSON源码分析的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: HPC学习(二)
- 下一篇: Swift开发:使用SwiftyJSON