import HandyJSON
class PersonHJ: HandyJSON {
var username: String?
var age: Int?
var weight: Double!
var sex: Bool!
var locatoin: String?
var three_day_forecast: [ForecastHJ]?
required init() {
}
}
class ForecastHJ: HandyJSON {
var conditions: String?
var day: String?
var temperature: Double!
required init() {
}
}
let jsonString: String = "{\"username\":\"yuhanle\",\"age\":18,\"weight\":65.4,\"sex\":1,\"location\":\"Toronto, Canada\",\"three_day_forecast\":[{\"conditions\":\"Partly cloudy\",\"day\":\"Monday\",\"temperature\":20},{\"conditions\":\"Showers\",\"day\":\"Tuesday\",\"temperature\":22},{\"conditions\":\"Sunny\",\"day\":\"Wednesday\",\"temperature\":28}]}"
let dataFromString = jsonString.data(using: .utf8, allowLossyConversion: false)
do {
let json = try JSON(data: dataFromString!)
print(json["username"], json["weight"], json["three_day_forecast"][0]["conditions"])
} catch let error as NSError {
print ("Error: \(error.domain)")
}
MJExtension
最后看下一下 MJExtension,作为一个从 ObjC 年代就开始流程的转换框架,在如今使用的人仍然很多,但是对于 Swift 的集成却不是特别友好,官方 issue 列表中经常都会有申请支持 swift 的呼声!
import MJExtension
class PersonMJ: NSObject {
@objc var username: String?
@objc var age = 0
@objc var weight = 0.0
@objc var sex = false
@objc var location: String?
@objc var three_day_forecast: [ForecastMJ]?
}
class ForecastMJ: NSObject {
@objc var conditions: String?
@objc var day: String?
@objc var temperature = 0.0
}
尽管在支持上不是特别友好,但是在自定义 Model 的过程中,应该是最轻松的一款,但是在升级 Swift 4 之后,需要在属性前添加 @objc 才可以正常使用,否则转换失败。具体情况可参考:Swift 4 字典转模型失败
let maxCount = 10000
func testHandyJSON(json: String) -> Void {
var start = CFAbsoluteTimeGetCurrent()
var people: PersonHJ = PersonHJ()
for _ in 0..<maxCount {
people = PersonHJ.deserialize(from: json)!
}
var executionTime = CFAbsoluteTimeGetCurrent() - start
print("HandyJSON deserialize time totals: ", executionTime)
start = CFAbsoluteTimeGetCurrent()
var res = ""
for _ in 0..<maxCount {
res = people.toJSONString()!
}
executionTime = CFAbsoluteTimeGetCurrent() - start
print(res)
print("HandyJSON toJSONString time totals: ", executionTime)
}
到了 Swift 年代,第三方库 SwiftyJSON 和 ObjectMapper 都曾经作为 JSON 转换的中流砥柱,只是这两者还是免不了“手动指定字段和JSON字典映射关系”的工作。于是阿里想了个黑科技(HandyJSON),通过分析Swift数据结构在内存中的布局,自动分析出映射关系,进一步降低开发者使用的成本。
如今我们就有多个选择:ObjectMapper、HandyJSON、SwiftyJSON、MJExtension 等
其实我们在日常开发中,对于 JSON 数据的处理有两大需求:
框架简介
ObjectMapper
先看 ObjectMapper : Model 类必须实现 Mappable 协议,即实现 init 和 mapping 函数;适合跟 Alamofire 配合。但是 mapping 函数实现起来过于臃肿耗时,只能借助插件来快速完成。
j2s 是一个 macOS app 能够将 JSON 对象转成 Swift 结构体
HandyJSON
再看 HandyJSON, 写起来比较方便,类和结构体要求继承于 HandyJSON、枚举要继承于 HandyJSONEnum。
比ObjectMapper使用上要简单, 不用写mapping函数那么多代码了。
SwiftyJSON
看 SwiftyJSON:取字段值使用比较方便, 但是然并卵? SwiftyJSON 不支持转 Model,如果你只是想要解析某几个字段,那么 SwiftyJSON 是不二选择, 而且适用于 Alamofire。
MJExtension
最后看下一下 MJExtension,作为一个从 ObjC 年代就开始流程的转换框架,在如今使用的人仍然很多,但是对于 Swift 的集成却不是特别友好,官方 issue 列表中经常都会有申请支持 swift 的呼声!
尽管在支持上不是特别友好,但是在自定义 Model 的过程中,应该是最轻松的一款,但是在升级 Swift 4 之后,需要在属性前添加 @objc 才可以正常使用,否则转换失败。具体情况可参考:Swift 4 字典转模型失败
另外还有一种情况,就是关于整型属性,需要给定初试值,也就是说,MJExtension 无法序列化/反序列化整型。解决办法很简单, 就是赋个默认值, 即将Optional整型变为整型就可以。
运行耗时
我们准备了一小段 JSON 数据,循环解析 10000 次,来分析几大框架的运行耗时:
以 HandyJSON 为例,在开始处理数据和结束时,记录时间差,时间差的结果每次会有波动
最终记录得到的结果对比图
结果有点出乎意料,HandyJSON 的黑魔法纵然很强大,这也导致了耗时的问题,相比较而言,不太友好的 MJExtension 速度最快。
总结
对于应用开发来说,JSON 数据序列化和反序列号的操作必不可少,上述分析的效率和性能问题,也应该多考虑,选择合适的框架很重要,学习和踩坑也是并存的。
另外,Swift 支持 Codable 协议,对这个需求的处理也有很大的支持!
参考链接