转载于:http://swiftist.org/topics/124#2
最近看了一些网络请求的例子,发现Swift在解析JSON数据时特别别扭,总是要写一大堆的downcast(as?
)和可选(Optional
),看?
号都看花了。随后发现了这个库SwiftyJSON,问题迎刃而解,灰常优雅和Swifty!
简单介绍下这个库(内容译自SwiftyJSON的README
):
Swift语言是一种严格的类型安全语言,它要求我们显示的设置类型,并帮助我们写出更少bug的代码。但是当处理JSON这种天生就是隐式类型的数据结构,就非常麻烦了。
拿Twitter中timeline API返回的数据为例:
[
{
......
"text": "just another test",
......
"user": {
"name": "OAuth Dancer",
"favourites_count": 7,
"entities": {
"url": {
"urls": [
{
"expanded_url": null,
"url": "http://bit.ly/oauth-dancer",
"indices": [
0,
26
],
"display_url": null
}
]
}
......
},
"in_reply_to_screen_name": null,
},
......]
Swift中的解析代码会是这样:
let jsonObject : AnyObject! = NSJSONSerialization.JSONObjectWithData(dataFromTwitter, options: NSJSONReadingOptions.MutableContainers, error: nil)
if let statusesArray = jsonObject as? NSArray{
if let aStatus = statusesArray[0] as? NSDictionary{
if let user = aStatus["user"] as? NSDictionary{
if let userName = user["name"] as? NSDictionary{
//终于我们得到了`name`
}
}
}
}
不好吧。就算是换成可选链式调用,也还是一团糟:
let jsonObject : AnyObject! = NSJSONSerialization.JSONObjectWithData(dataFromTwitter, options: NSJSONReadingOptions.MutableContainers, error: nil)
if let userName = (((jsonObject as? NSArray)?[0] as? NSDictionary)?["user"] as? NSDictionary)?["name"]{
//上面这一堆是个啥??
}
你只要这样做就行了:
let json = JSONValue(dataFromNetworking)
if let userName = json[0]["user"]["name"].string{
//恩~ `name`到手,就这么简单
}
你不需要考虑可选类型的拆包和是否能拆包的判断,这些都自动完成了:
let json = JSONValue(dataFromNetworking)
if let userName = json[999999]["wrong_key"]["wrong_name"].string{
//冷静,嘿嘿~ 调用不存在的["wrong_key]也不会crash滴, .string最终能安全的返回一个字符串或`nil`
}
let json = JSONValue(jsonObject)
switch json["user_id"]{
case .JString(let stringValue):
let id = stringValue.toInt()
case .JNumber(let doubleValue):
let id = Int(doubleValue)
default:
println("ooops!!! JSON Data is Unexpected or Broken")
看到这个库之后,一方面很爽终于有合适的处理JSON的方法了;另一方面心里其实很好奇它是怎么做到的?
通过看源代码,才了解到它是创建了一个JSONValue
枚举,这个枚举中有一个JInvalid
类型。当使用json字符串来构造JSONValue
对象时,如果无法构建成功,就会返回这个JInvalid
枚举对象,然后对这个JInvalid
枚举对象继续处理,会继续返回JInvalid
。直到对其调用string
, number
, bool
之类来获取Swift中的数据类型值时,才会返回nil
。
这套机制是类似于Optional<T>
可选类型的,但是不同的是,Optional中对nil
调用方法会crash,但JSONValue
中对JInvalid
调用方法不会crash,而是继续返回JInvalid
。这样使用时就不用写一堆?
号啦,反正不会出错滴。
同时,它给JSONValue
枚举还创建了其它json中使用到的各种类型JNumber
, JString
, JBool
,它们能通过构造器将原始值包装起来,然后最后通过对应的number
,string
,bool
等属性方法来拆包,得到原始值。
推荐大家也读读这个库的源代码,其对enum
的使用灰常巧妙!