使用原生库解析JSON

(挖坑自己跳系列四)
以为实现了xml的解析,我就能拿到所有想要的数据,可是经过几次尝试,发现有的API失效了!😱无论我怎么尝试,有的数据就是拿不到,苦恼了好久,灵光一闪:前阵子买的surge可以派上用场了!不知道surge是啥的我给解释一下,是个iOS App,利用iOS9的特性能给设备做个全局代理,前阵子大家纷纷用来流畅FQ,已下架。对我来说,用来过滤下广告正好,偶尔还能看看http log。
看了下自己手机上的第三方客户端,request居然直接是网页,看来是直接解析网页了,这个太高深、放弃;只好去下载官方客户端来看,在网页看同样的请求,返回居然换成JSON了……😥
还能说啥呢,去找找JSON怎么解析呗!这次看了看,似乎比XML简单多了……先拿数据:

let url = NSURL(string:TESTURL)!
guard data = NSData(contentsOfURL: url)  else{
    print("Can't get any data")
    exit(0)
}

然后解析出来:

你看到的是非授权版本!爬虫凶猛,请尊重知识产权!

转载请注明出处:http://conanwhf.github.io/2015/12/15/swift_json/

访问原文「使用原生库解析JSON」获取最佳阅读体验并参与讨论

do {
    let json = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers)
    // TODO:
} catch {
    print("JSONObjectWithData: \(error)")
}

问题是,明明看起来正常的数据,每次解析都报错!开始以为是unicode编码的问题(我的数据里有中文),一头扎进编码里……后来花了好长时间Debug,才发现关键在于我拿到的数据在头尾多了个“CALLBACK({正常的JSON数据})”!手动处理去掉了这个壳,数据才终于正常了……关于这个数据形式,我原本揣测是服务器和官方客户端之间的约定,心里暗骂了他们好多遍(原谅我的无知吧),直到偶然看到了这一段:

为了便于客户端使用数据,逐渐形成了一种非正式传输协议,人们把它称作JSONP,该协议的一个要点就是允许用户传递一个callback参数给服务端,然后服务端返回数据时会将这个callback参数作为函数名来包裹住JSON数据,这样客户端就可以随意定制自己的函数来自动处理返回数据了。

这样就解释了为什么自带的库不能处理这种情况(_非正式协议_),以及为何我用的在线JSON转换器可以处理(_都是喜欢偷偷商量个后门程序员干的哇!_),之前我连啥是JSON都没见过,没注意到只怪自己读书少……😭
言归正传。当JSON数据解析完成后,就可以直接拿来用了。API已经返回一个层层嵌套的完整数据字典,供你享用,这一点可比XML方便多了。我们要做的就是强制转换,然后拿数据(当然你也许需要转化为自己的数据结构,称为_模型化_,此处不表)。以简单的数据为例:

{
        "person": {
            "employees": 
            [
                {"id": 1, "firstName": "Bill", "lastName": "Gates"},
                {"id": 2, "firstName": "George", "lastName": "Bush"}
            ],
        "boss": [
                {"id": 1, "firstName": "Bill", "lastName": "Gates"}
        ]
}}

强制转换成字典: 

let dic : NSDictionary? = json["person"]() as? NSDictionary

这时的dic就是个包括了employees和boss的字典:[“employess”:[…], “boss”:[…]],将employess的数据再次强制转换成数组:

let arr : NSArray? = dic?["employees"]() as? NSArray

你会得到一个包含两个元素的数组,每个元素都是一部雇员信息的字典。够简单吧?如果你需要,源码传送门:这里
后记
JSON确实是个很好用的数据表达方式,也难怪会如此流行。就我个人的感受来说,如果你只是需要从服务器端拿一些少量(我指的是种类)数据,那么用原生的库就行了,简单方便;如果你需要的是整个数据结构,那么手动慢慢填充转换也还是挺累的,建议引入第三方库建模。