Swift - SwiftyJSON的使用详解(附样例,用于JSON数据处理)
作者:hangge | 2016-01-08 08:51
(本文代码已升级至Swift4)
2,SwiftyJSON的优点
同 JSONSerializationSwiftyJSON 相比,在获取多层次结构的JSON数据时。SwiftyJSON不需要一直判断这个节点是否存在,是不是我们想要的class,下一个节点是否存在,是不是我们想要的class…。同时,SwiftyJSON内部会自动对optional(可选类型)进行拆包(Wrapping ),大大简化了代码。
1,SwiftyJSON介绍与配置
SwiftyJSON是个使用Swift语言编写的开源库,可以让我们很方便地处理JSON数据(解析数据、生成数据)。
GitHub地址:https://github.com/SwiftyJSON/SwiftyJSON
使用配置:直接将 SwiftyJSON.swift 添加到项目中即可。
使用配置:直接将 SwiftyJSON.swift 添加到项目中即可。
同 JSONSerializationSwiftyJSON 相比,在获取多层次结构的JSON数据时。SwiftyJSON不需要一直判断这个节点是否存在,是不是我们想要的class,下一个节点是否存在,是不是我们想要的class…。同时,SwiftyJSON内部会自动对optional(可选类型)进行拆包(Wrapping ),大大简化了代码。
下面通过几个样例作为演示。
(2)使用JSONSerializationSwiftyJSON解析
比如我们要取第一条联系人的第一个电话号码,每个级别都判断就很麻烦,代码如下:
(3)使用SwiftyJSON解析:
不用担心数组越界,不用判断节点,拆包什么的,代码如下:
如果没取到值,还可以走到错误处理来了,打印一下看看错在哪:
3,获取网络数据,并使用SwiftyJSON解析
除了解析本地的JSON数据,我们其实更常通过url地址获取远程数据并解析。
(1)与URLSession结合
(2)与Alamofire结合
4,获取值
(2)使用简单的数据类型创建JSON对象
(3)使用数组或字典数据创建JSON对象
(1)比如我们有一个如下的JSON数据,表示联系人集合:
[ { "name": "hangge", "age": 100, "phones": [ { "name": "公司", "number": "123456" }, { "name": "家庭", "number": "001" } ] }, { "name": "big boss", "age": 1, "phones": [ { "name": "公司", "number": "111111" } ] } ]为便于测试比较,我们先将JSON格式的字符串转为Data:
let jsonStr = "[{\"name\": \"hangge\", \"age\": 100, \"phones\": [{\"name\": \"公司\",\"number\": \"123456\"}, {\"name\": \"家庭\",\"number\": \"001\"}]}, {\"name\": \"big boss\",\"age\": 1,\"phones\": [{ \"name\": \"公司\",\"number\": \"111111\"}]}]" if let jsonData = jsonStr.data(using: String.Encoding.utf8, allowLossyConversion: false) { //......... }
(2)使用JSONSerializationSwiftyJSON解析
比如我们要取第一条联系人的第一个电话号码,每个级别都判断就很麻烦,代码如下:
if let userArray = try? JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) as? [[String: AnyObject]], let phones = userArray?[0]["phones"] as? [[String: AnyObject]], let number = phones[0]["number"] as? String { // 找到电话号码 print("第一个联系人的第一个电话号码:",number) }即使使用optional来简化一下,代码也不少:
if let userArray = try? JSONSerialization.jsonObject(with: jsonData, options: .allowFragments) as? [[String: AnyObject]], let number = (userArray?[0]["phones"] as? [[String: AnyObject]])?[0]["number"] as? String { // 找到电话号码 print("第一个联系人的第一个电话号码:",number) }
(3)使用SwiftyJSON解析:
不用担心数组越界,不用判断节点,拆包什么的,代码如下:
let json = try! JSON(data: jsonData) if let number = json[0]["phones"][0]["number"].string { // 找到电话号码 print("第一个联系人的第一个电话号码:",number) }
let json = try! JSON(data: jsonData) if let number = json[0]["phones"][0]["number"].string { // 找到电话号码 print("第一个联系人的第一个电话号码:",number) }else { // 打印错误信息 print(json[0]["phones"][0]["number"]) }
除了解析本地的JSON数据,我们其实更常通过url地址获取远程数据并解析。
(1)与URLSession结合
//创建URL对象 let url = URL(string:"http://www.hangge.com/getJsonData.php") //创建请求对象 let request = URLRequest(url: url!) let dataTask = URLSession.shared.dataTask(with: request, completionHandler: {(data, response, error) -> Void in if error != nil{ print(error) }else{ let json = try! JSON(data: data!) if let number = json[0]["phones"][0]["number"].string { // 找到电话号码 print("第一个联系人的第一个电话号码:",number) } } }) as URLSessionTask //使用resume方法启动任务 dataTask.resume()
(2)与Alamofire结合
//创建URL对象 let url = URL(string:"http://www.hangge.com/getJsonData.php")! Alamofire.request(url).validate().responseJSON { response in switch response.result.isSuccess { case true: if let value = response.result.value { let json = JSON(value) if let number = json[0]["phones"][0]["number"].string { // 找到电话号码 print("第一个联系人的第一个电话号码:",number) } } case false: print(response.result.error) } }
(1)可选值获取(Optional getter)
通过.number、.string、.bool、.int、.uInt、.float、.double、.array、.dictionary、int8、Uint8、int16、Uint16、int32、Uint32、int64、Uint64等方法获取到的是可选择值,我们需要自行判断是否存在,同时不存在的话可以获取具体的错误信息。
使用 xxxValue 这样的属性获取值,如果没获取到的话会返回一个默认值。省得我们再判断拆包了。
(3)获取原始数据(Raw object)
5,设置值
6,下标访问(Subscript)
可以通过数字、字符串、数组类型的下标访问JSON数据的层级与属性。比如下面三种方式的结果都是一样的:
7,循环遍历JSON对象中的所有数据
(1)如果JSON数据是数组类型(Array)
(2)如果JSON数据是字典类型(Dictionary)
8,构造创建JSON对象数据
(1)空的JSON对象
通过.number、.string、.bool、.int、.uInt、.float、.double、.array、.dictionary、int8、Uint8、int16、Uint16、int32、Uint32、int64、Uint64等方法获取到的是可选择值,我们需要自行判断是否存在,同时不存在的话可以获取具体的错误信息。
//int if let age = json[0]["age"].int { print(age) } else { //打印错误信息 print(json[0]["age"]) } //String if let name = json[0]["name"].string { print(name) } else { //打印错误信息 print(json[0]["name"]) }(2)不可选值获取(Non-optional getter)
使用 xxxValue 这样的属性获取值,如果没获取到的话会返回一个默认值。省得我们再判断拆包了。
//If not a Number or nil, return 0 let age: Int = json[0]["age"].intValue //If not a String or nil, return "" let name: String = json[0]["name"].stringValue //If not a Array or nil, return [] let list: Array<JSON> = json[0]["phones"].arrayValue //If not a Dictionary or nil, return [:] let phone: Dictionary<String, JSON> = json[0]["phones"][0].dictionaryValue
(3)获取原始数据(Raw object)
let jsonObject = json.object as AnyObject let jsonObject = json.rawValue as AnyObject //JSON转化为Data let data = json.rawData() //JSON转化为String字符串 if let string = json.rawString() { //Do something you want } //JSON转化为Dictionary字典([String: AnyObject]?) if let dic = json.dictionaryObject { //Do something you want } //JSON转化为Array数组([AnyObject]?) if let arr = json.arrayObject { //Do something you want }
5,设置值
json[0]["age"].int = 101 json[0]["name"].string = "hangge.com" json[0]["phones"].arrayObject = [["name":"固话", "number":110],["name":"手机", "number":120]] json[0]["phones"][0].dictionaryObject = ["name":"固话", "number":100]
6,下标访问(Subscript)
可以通过数字、字符串、数组类型的下标访问JSON数据的层级与属性。比如下面三种方式的结果都是一样的:
//方式1 let number = json[0]["phones"][0]["number"].stringValue //方式2 let number = json[0,"phones",0,"number"].stringValue //方式3 let keys:[JSONSubscriptType] = [0,"phones",0,"number"] let number = json[keys].stringValue
(1)如果JSON数据是数组类型(Array)
for (index,subJson):(String, JSON) in json { print("\(index):\(subJson)") }
for (key,subJson):(String, JSON) in json[0] { print("\(key):\(subJson)") }
(1)空的JSON对象
let json: JSON = nil
(2)使用简单的数据类型创建JSON对象
//StringLiteralConvertible let json: JSON = "I'm a son" //IntegerLiteralConvertible let json: JSON = 12345 //BooleanLiteralConvertible let json: JSON = true //FloatLiteralConvertible let json: JSON = 2.8765
(3)使用数组或字典数据创建JSON对象
//DictionaryLiteralConvertible let json: JSON = ["I":"am", "a":"son"] //ArrayLiteralConvertible let json: JSON = ["I", "am", "a", "son"] //Array & Dictionary var json: JSON = ["name": "Jack", "age": 25, "list": ["a", "b", "c", ["what": "this"]]] json["list"][3]["what"] = "that" json["list",3,"what"] = "that" let path:[JSONSubscriptType] = ["list",3,"what"] json[path] = "that"
全部评论(23)
站长,swift4 获取网数据解析的那个地方用不了!
站长回复:我又测试了下是可以用的啊,不知你那边是报什么错误吗?
Alamofire.request(indexUrl).validate().responseJSON { response in
switch response.result.isSuccess {
case true:
if let value = response.result.value {
/*
http://www.hangge.com/blog/cache/detail_968.html
*/
let json = JSON(value)
print("json:",json["boxes"][1]["videos"][1])
}
case false:
print(response.result.error)
}
}
看来大哥的文章,基本都了解了.有个疑问,这里都是闭包. 这个 JSON(value) 怎么传出去给其他方法使用呢.
尝试过在 class里声明一个 lazy var jsondata JSON = JSON.null 可接收不了.估计是类型不同呢.
站长回复:外面你直接定义成 var jsondata:JSON? 就好了
您好,站长,我是一名新鸟,我已经能获取到json数据,但是却一直不能成功解析,请帮忙指导,谢谢
Alamofire.request("https://api.500px.com/v1/photos", method: .get, parameters: ["consumer_key":"Ay5qbibWqK1jzAgVNP72vnUaZwN0SL7diPuDlAxR"]).responseJSON { (json) in
let value = json.result.value
let jsons = JSON(value)
if let data = jsons["photos"][1]["id"].string{
print("解析成功")
print(data)
}else{
print("解析失败")
print(jsons["photos"][1]["id"])
}
站长回复:你把jsons["photos"][1]["id"].string 改成 jsons["photos"][1]["id"].int 就可以了。因为返回的id是数字,不是字符串。
站长 cell.textLabel?.text = channels[indexPath.row]["name"].stringValue 文本是.stringValue
cell.xxImageView.image = xx[indexPath.row]["img"] 应该是什么类型
站长回复:也是String类型,不过你这里得到的应该是图片名或者图片地址,还要先将其转为对应的UIImage再赋给 cell.xxImageView.image
{msg:"登录成功",code:1,UID:2}
这是post请求返回的数据
航哥,这样的数据怎样解析?
站长回复:
航哥,我想请问一下,我自定义一个类,然后传递这个类的数组,该如何在swift中将这个json数据转换为这个类的数组?
站长回复:你是想将JSON数据转换成对象模型吗?可以试试ObjectMapper,我之前也写过相关文章:Swift - 使用ObjectMapper实现模型转换1(JSON与Model的相互转换)
JSON: {
list = {
listimage = "http://113.140.75.202/APP/images/568505479484d.png";
listsubtitle = "\U6321\U4e0d\U4f4f\U7684\U8bf1\U60d1";
listtitle = "\U610f\U5927\U5229\U9999\U83c7\U814a\U80a0\U62ab\U8428";
price = "\Uffe5100";
};
lunbo = {
lunbo1 = "http://113.140.75.202/APP/images/lunbo1.png";
lunbo2 = "http://113.140.75.202/APP/images/lunbo2.png";
lunbo3 = "http://113.140.75.202/APP/images/lunbo3.png";
lunbo4 = "http://113.140.75.202/APP/images/lunbo4.png";
};
notice = {
noticetext = "\U75af\U72c2\U5f00\U5b66\U5b63 \U4f18\U60e0\U9001\U4e0d\U505c";
noticetitle = "http://113.140.75.202/APP/images/youhui.png";
};
recommend = {
recommendimage = "http://113.140.75.202/APP/images/huazhuangpin.png";
recommendimage2 = "http://113.140.75.202/APP/images/huazhuangp.png";
recommendimage3 = "http://113.140.75.202/APP/images/time.png";
recommendimage4 = "http://113.140.75.202/APP/images/xie.png";
recommendimage5 = "http://113.140.75.202/APP/images/bao.png";
recommendimage6 = "http://113.140.75.202/APP/images/erji.png";
recommendtitle = "\U6bcf\U65e5\U75af\U62a2";
recommendtitle2 = "";
recommendtitle3 = "\U6587\U827a\U9752\U5e74";
recommendtitle4 = "\U4f1a\U5458\U4e13\U4eab";
recommendtitle5 = "\U6f6e\U54c1";
recommendtitle6 = "\U4e2a\U60273C";
subtitle = "\U72ec\U5230\U597d\U773c\U5149";
subtitle2 = "";
subtitle3 = "";
subtitle4 = "\U7279\U6743high\U4e0d\U505c";
subtitle5 = "\U4f60\U6709freestyle\U5417\Uff1f";
subtitle6 = "";
};
}
上面是服务器返回的数据,要怎么才能赋到字典里 也有人说这本身就可以用 但是不知道要怎么提取出来 新手 在线等
站长回复:如果你是想把JSON数据转成Dictionary的话,直接使用自带的JSONSerialization进行转换就好了。具体用法可以参考我的这篇文章:Swift - 解析JSON数据(内置JSONSerialization与第三方JSONKit)
{
"pay_params" : "{\"url\":\"http:\\\/\\\/192.168.0.114:5000\\\/pay-web\\\/pay?ordernum=20170609145353118966\"}",
"pay_type_id" : 99,
"ordernum" : "20170609145353118966"
}
上面是后台给我的数据, 里面的URL用SwiftyJSON拿不出来,
站长回复:JSON数据有问题(url那部分),需要后台修改下,正常应该是下面这种形式:
是不是上面的那个PHP链接无效了啊???
站长回复:那个链接是我随便写的,你可以随便找个数据地址进行测试,或者在本地搭建个Web服务器也是可以的。
航哥 我新手 有demo看吗?
站长回复:你可以随便新建个工程,把文字中的代码放进去运行就可以看到效果了。
航哥, 请问cocopods 里面是不是SwitftyJSON 和 Alamofire 这两个库还没有更新?
站长回复:现在应该都更新了。
swift3.0后一直报错啊
站长回复:我把代码更新成Swift3了,现在可以使用了。
站长,可以用swiftyjson使json数据转换成nsdata的?可以的话,还请站长教教我
站长回复:文章4(3)有写啊,//JSON转化为Data
let data = json.rawData()
手动挡分享!
站长回复:谢谢支持。
很好用····
站长回复:谢谢支持,欢迎常来看看,我会继续创作更多的文章分享给大家。
站长,这是我用open weather map API请求到的json数组,但是这个数据太多了,很多我都不需要,而且格式也不是很明白,按照api说的那样list.main.temp也不能解析,您能帮我看下嘛
http://api.openweathermap.org/data/2.5/forecast/city?id=1816670&APPID=84135ced4a43a78933b153b9dc2fc609
站长回复:你用的是SwiftyJSON来解析json数据吧,list节点下面是数组数据,如果要取到里面的main.temp数据,需要进行遍历:
func parseJsonData(data: NSData) -> [Loan] {
var loans = [Loan]()
do {
let jsonResult = try NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers) as? NSDictionary
// Parse JSON data
let jsonLoans = jsonResult?["loans"] as! [AnyObject]
for jsonLoan in jsonLoans {
let loan = Loan()
loan.name = jsonLoan["name"] as! String
loan.amount = jsonLoan["loan_amount"] as! Int
loan.use = jsonLoan["use"] as! String
let location = jsonLoan["location"] as! [String:AnyObject]
loan.country = location["country"] as! String
loans.append(loan)
}
} catch {
print(error)
}
return loans
}
航哥,请问能不能看一下这一段代码怎么用SwiftyJSON改写= = 谢谢了
站长回复:这个我就不改写了,因为文章里已经很详细地讲解了SwiftyJSON的用法。你如果都看完我相信你应该也能实现的。
航哥,请问可不可以直接把json数据直接存储到指定的文件中?如果可以改怎么实现呢?我用writeToFile不能储存,是否需要转换成字典?
站长回复:你说的json数据是指json格式的字符串吗,不是的话你可以先转成String再用writetofile写到文件中
航哥麻烦你看下下面的代码
let url = "http://api.avatardata.cn/TechNews/Query?key=27e9d90b6c9b436a89c3d2b746e52c81&page=1&rows=50"
let urlstring = NSURL(string: url)
let request:NSURLRequest = NSURLRequest(URL: urlstring!)
// _ = NSData()
let session = NSURLSession.sharedSession()
let dataTask = session.dataTaskWithRequest(request,
completionHandler: {(data, response, error) -> Void in
if error != nil{
print(error?.code)
print(error?.description)
}else{
let json = JSON(data: data!)
let array = json["result"]
let dic = array[1] as! Dictionary<String ,AnyObject>
print(dic)
}
})as NSURLSessionTask
dataTask.resume()
我在 这里对 let dic = array[1] as! Dictionary<String ,AnyObject> 然后报错是Cast from 'String?' to unrelated type 'Dictionary<String, AnyObject>' always fails,我想是不是JSON中自己定义了字典类型这个字典类型和源生的有什么不一样啊?,能不能编写中直接像使用Dictionary来调用官方的方法呢??
站长回复:试试 let dic = array[1].dictionaryObject
非常非常非常感谢,尤其是利用了Alamofire和SwiftyJSON真是太棒了。我是一个初学者,这个对我太有帮助了,刚开始运行还有些一直不出,最后我尝试把" if let number = json[0]["phones"][0]["number"].string { " 这行中的三个[0] 去掉就正常了,不知为何?
站长回复:检查下你的json数据结构是不是和我文章里的不一样(文章最上方)。对于数组类型的数据,都是要通过下标访问其中的数据的。
let json = JSON(data: jsonData)
if let number = json[0]["phones"][0]["number"].string {
// 找到电话号码
print("第一个联系人的第一个电话号码:",number)
}
JSON报错use of unresolved identifier Json
站长回复:你是不是代码写错了,把json写成Json了
强强
站长回复:欢迎常来看看,我会持续创作更新的。
很实用的工具,学习了,给航哥点赞
站长回复:^_^