如果是Java开发者, 只有2个选择Gson或者fastjson。
如果是Swift开发者, 那么就有5个选择:ObjectMapper、AlamofireObjectMapper、HandyJSON、SwiftyJSON和MJExtension。 到底用哪个?
其实我们对json三方库有2个基本要求:
1、 json和model互相转换(Android Studio有Gson format插件,但Xcode没有类似功能)
2、 因为服务端大多数使用Java语言编写, 所以json里可能有null,但是Swift语言的空是用nil表示, 我们希望三方库能正确处理空值情况(对象Optional类型)。
先看ObjectMapper : Model类必须实现Mappable协议,即实现init和mapping函数; 适合跟Alamofire配合。但是mapping函数过于臃肿耗时,如果有插件生成还可以。
class User: Mappable {
var name: String?
var age: Int?
init() {
}
required init?(map: Map) {
}
func mapping(map: Map) {
name <- map["username"]
age <- map["age"]
}
}
let user = User()
user.age = 1
user.name = nil
let json = user.toJSONString()
print(json!)
let user2 = User(JSONString: "{\"name\":null, \"age\":1}") //模拟服务器响应
print("\(String(describing: user2?.name)) \(user2?.age ?? 2)")
结果: ["age": 1]
nil 1
再看HandyJSON, 写起来比较方便,类和结构体要求继承于HandyJSON、枚举要继承于HandyJSONEnum。
class Animal: HandyJSON {
var name: String?
var age: Int?
required init() {
}
}
let animal = Animal()
animal.age = 1
let json = animal.toJSONString()
print(json!)
let object = Animal.deserialize(from: "{\"name\":null, \"age\":1}") //模拟服务器响应
print("\(object!.name) \(object!.age) ")
{"age":1}
nil Optional(1)
看SwiftyJSON: 取字段值使用比较方便, 但是然并卵? SwiftyJSON不支持转Model, 如果你只是想要解析某几个字段,那么SwiftyJSON是不二选择, 而且适用于Alamofire。
let original: JSON = [ //构造函数JSON(data: Data)适用于网络响应,即在Alamofire使用
"first_name": "John",
"age": 20,
"skills": ["Coding", "Reading"],
"address": [
"street": "Front St",
"zip": "12345",
]
]
//print(original["address","street"]) //嵌套取值很方便,使用逗号或方框分隔
print(original["address"]["street"])
print(original["nocolumn"]["key"]) //乱写的值,即使键错误也不会报错
输出:
Front St //找到了嵌套的key
null //没找到key时输出null
OC版本的MJExtension,它的坑在于无法解析Optional Int, 而且如果json里有这个键值的话其它字段也无法解析。
class People: NSObject {
var name: String?
var age: Int? //请注意:MJExtension不能解析Optional Int类型
}
let people = People()
people.age = 1;
people.name = "zhangsan"
let json = people.mj_JSONString()
print(json!) //序列化后age被抛弃了。。。
let object = People.mj_object(withKeyValues: "{\"name\":\"zhangsan\",\"age\":1}") //因为有Optional类型age字段,无法解析
print("\(object?.name)\(object?.age)")
输出:
{"name":"zhangsan"}
Optional("zhangsan")nil
完全找不到age参数的影子, 说明MJExtension无法序列化/反序列化整型。
解决办法很简单, 就是赋个默认值, 即将Optional整型变为整型就可以了。
class People: NSObject {
var name: String?
var age = 0 //赋默认值
}
重新运行后输出:
{"age":1,"name":"zhangsan"}
Optional("zhangsan")Optional(1)
MJExtension已经很久不维护了, 不建议使用。
综上, 推荐使用HandyJSON, 理由是写法简便且能支持json和model互转的需求, 而且一直在更新维护!