一、HandyJSON原理
HandyJSON是一个轻量级的JSON转换库,它可以将JSON数据转换成Swift对象。使用HandyJSON可以简化Swift对象的JSON解析操作,将大量的解析代码简化为数行代码。HandyJSON的原理是将JSON数据转化为Swift模型,在Swift模型中实现属性与JSON中的键值对的映射关系,从而实现JSON数据的转换。
二、HandyJSON如何自定义解析
在解析JSON数据时,有些情况下需要对JSON数据进行一些处理后才能将其转换成Swift模型。在HandyJSON中,我们可以通过实现HandyJSON协议中的两个方法来实现自定义解析。第一个方法是mapping(mapper: Mapper)
,通过手动解析来将JSON中的值映射到Swift属性上。第二个方法是jsonDidTransform(mapping: JSONTransform)
,允许我们在进行数据转换时使用自定义的JSON转换类型。
class User: HandyJSON {
var name: String?
var age: Int?
func mapping(mapper: Mapper) {
name <- mapper["nickName"]
age <- mapper["ages"]
}
}
三、HandyJSON源码解析
HandyJSON源码中最核心的部分是它的解析器JASONDeserializer
。JASONDeserializer
是一个递归解析器,它可以将任意的JSON数据解析成Swift对象。在解析过程中,JASONDeserializer
会使用一个JSON字典栈来保存当前解析所在的层数、当前解析的JSON数据和解析后生成的Swift对象。
四、HandyJSON数组转模型
在实际开发中,需要经常将一个JSON数组转换成一个模型数组。HandyJSON提供了较为简便的实现方法。在模型中定义一个数组类属性(可以不赋初始值),并且让这个数组属性遵循HandyJSON的协议。在初始化过程中,使用HandyJSON提供的arrayIn<Type: HandyJSON>
函数即可完成将JSON数组转换为对应的模型数组。
class UserModel: HandyJSON {
var users: [User]?
required init() {}
}
let userModel = UserModel.deserialize(from: jsonString)
let users = userModel?.users
五、HandyJSON自定义解析
有些JSON数据不符合我们的要求,我们需要使用一些特定的方法,对其进行自定义的解析。实现HandyJSON协议的mapping
方法即可简单地达到这个目的。在mapping
方法中可以用<-
符号将Swift对象映射到特定的JSON对象中。
class CustomUser: HandyJSON {
var name: String?
var age: Int?
required init() {}
func mapping(mapper: Mapper) {
name <- mapper["nickName"]
age <- (mapper["ages"], transformOf(customInitializer))
}
func customInitializer(ratio: String?) -> Int? {
guard let ratio = ratio else {
return 0
}
return Int(ratio)
}
}
六、HandyJSON解析网络请求
当我们使用API请求获取JSON数据时,HandyJSON也可以方便的将JSON数据转换为模型。在Alamofire的基础上,我们只需要将JSON数据作为参数传递给HandyJSON的简易解析方法即可。
Alamofire.request(apiUrl).responseJSON { (dataResponse) in
if let value = dataResponse.result.value,
let users = [User].deserialize(from: value as? String) {
completion(users.compactMap { $0 })
} else {
completion(nil)
}
}
七、HandyJSON在iOS15闪退
在iOS15中,关于HandyJSON数组转模型的使用存在着某些问题,存在内存泄漏、上下文不对等问题,可能会导致闪退。解决方法是可以将手动转换成Codable对其解析(相对于它更安全)或者升级HandyJSON到4.3.0+版本。
class User: Codable {
var name: String
var age: Int
}
let users = try JSONDecoder().decode([User].self, from: jsonData)