一 简介
二 特性
三 安装使用以及封装
四 使用示例
五 项目使用示例
一 简介
HandyJSON
是一个用于Swift
语言中的JSON
序列化/反序列化库。
与其他流行的Swift JSON
库相比,HandyJSON
的特点是,它支持纯swift
类,使用也简单。它反序列化时(把JSON转换为Model)不要求Model
从NSObject
继承(因为它不是基于KVC机制
),也不要求你为Model
定义一个Mapping
函数。只要你定义好Model
类,声明它服从HandyJSON
协议,HandyJSON
就能自行以各个属性的属性名为Key
,从JSON
串中解析值。
HandyJSON
目前依赖于从Swift Runtime
源码中推断的内存规则,任何变动我们将随时跟进。
二 特性
- 序列化
Model
到JSON、从JSON反序列化
到Model
- 自然地以
Model
的属性名称作为解析JSON
的Key
,不需要额外指定- 支持
Swift
中大部分类型- 支持
class
、struct
定义的Model
- 支持自定义解析规则
- 类型自适应,如
JSON
中是一个Int
,但对应Model
是String
字段,会自动完成转化
三 安装使用以及封装
3.1 安装
我使用的是cocopod
进行包引入管理,修改Prodfie
文件,添加如下代码:
pod 'HandyJSON'
3.2 封装
为了方便我们项目中的使用,我们一般都会在做一层封装
,方便库的以后升级替换
,以及方便日常业务逻辑的处理
JsonUtil.swift
import UIKit
import HandyJSON
class JsonUtil: NSObject {
/**
* Json转对象
*/
static func jsonToModel(_ jsonStr:String,_ modelType:HandyJSON.Type) ->BaseModel {
if jsonStr == "" || jsonStr.count == 0 {
#if DEBUG
print("jsonoModel:字符串为空")
#endif
return BaseModel()
}
return modelType.deserialize(from: jsonStr) as! BaseModel
}
/**
* Json转数组对象
*/
static func jsonArrayToModel(_ jsonArrayStr:String, _ modelType:HandyJSON.Type) ->[BaseModel] {
if jsonArrayStr == "" || jsonArrayStr.count == 0 {
#if DEBUG
print("jsonToModelArray:字符串为空")
#endif
return []
}
var modelArray:[BaseModel] = []
let data = jsonArrayStr.data(using: String.Encoding.utf8)
let peoplesArray = try! JSONSerialization.jsonObject(with:data!, options: JSONSerialization.ReadingOptions()) as? [AnyObject]
for people in peoplesArray! {
modelArray.append(dictionaryToModel(people as! [String : Any], modelType))
}
return modelArray
}
/**
* 字典转对象
*/
static func dictionaryToModel(_ dictionStr:[String:Any],_ modelType:HandyJSON.Type) -> BaseModel {
if dictionStr.count == 0 {
#if DEBUG
print("dictionaryToModel:字符串为空")
#endif
return BaseModel()
}
return modelType.deserialize(from: dictionStr) as! BaseModel
}
/**
* 对象转JSON
*/
static func modelToJson(_ model:BaseModel?) -> String {
if model == nil {
#if DEBUG
print("modelToJson:model为空")
#endif
return ""
}
return (model?.toJSONString())!
}
/**
* 对象转字典
*/
static func modelToDictionary(_ model:BaseModel?) -> [String:Any] {
if model == nil {
#if DEBUG
print("modelToJson:model为空")
#endif
return [:]
}
return (model?.toJSON())!
}
}
说明:这里我封装了5个方法,Json
转对象,Json
转数组对象
,字典
转对象
,对象
转JSON
,对象
转字典
,基本覆盖了我们日常开发的常用操作,与这个工具类相对应的,还有一个公共的基础module
类
BaseModel.swift
import UIKit
import HandyJSON
class BaseModel: HandyJSON {
// var date: Date?
// var decimal: NSDecimalNumber?
// var url: URL?
// var data: Data?
// var color: UIColor?
required init() {}
func mapping(mapper: HelpingMapper) { //自定义解析规则,日期数字颜色,如果要指定解析格式,子类实现重写此方法即可
// mapper <<<
// date <-- CustomDateFormatTransform(formatString: "yyyy-MM-dd")
//
// mapper <<<
// decimal <-- NSDecimalNumberTransform()
//
// mapper <<<
// url <-- URLTransform(shouldEncodeURLString: false)
//
// mapper <<<
// data <-- DataTransform()
//
// mapper <<<
// color <-- HexColorTransform()
}
}
说明:封装的基础model
类。开发中,我们自定义的model
继承此model
即可省去了每次都要引入 “import HandyJSON”
,以及每次都要实现“required init() {}”
方法,子类如果要自定义解析规则,重写mapping
方法即可
四 使用示例
基于以上封装的类我们实现几个示例做具体说明,主要有以下几个示例:
- Json转模型 (常用)
- Json数组转模型 (常用)
- 字典转模型
- 模型转Json
- 模型转字典
- json与嵌套的模型相互转换特殊类型字段转换,日期类型,数字类型,颜色
1. Json转模型 (常用)
JsonToModel.swift
import UIKit
class JsonToModel: BaseModel {
var id :Int?
var color:String?
var name:String?
}
fileprivate func jsonTomodel(){
let jsonString = "{\"id\":12345,\"color\":\"black\",\"name\":\"cat\"}"
let model:JsonToModel = JsonUtil.jsonToModel(jsonString,JsonToModel.self) as! JsonToModel
print(model.name as Any)
print(model.color as Any)
print(model.id as Any)
}
说明:调用jsonToModel(_ jsonStr:String,_ modelType:HandyJSON.Type)
,传入两个参数,第一个参数是要转换的Json
字符串,第二个参数是要转换的model
类的class
,因为公共类中统一返回的都是BaseModel
类型,所以这里要调用 as!
转换成具体的子类类型。
2. Json数组转模型 (常用)
JsonArrayToModel.swift
import UIKit
class JsonArrayToModel: BaseModel {
var name:String?
var id :String?
}
//json数组转模型
fileprivate func jsonArrayTomodel() {
let jsonArrayString: String = "[{\"name\":\"Bob\",\"id\":\"1\"}, {\"name\":\"Lily\",\"id\":\"2\"}, {\"name\":\"Lucy\",\"id\":\"3\"}]"
let cats = JsonUtil.jsonArrayToModel(jsonArrayString, JsonArrayToModel.self) as! [JsonArrayToModel]
for model:JsonArrayToModel in cats {
print(model.name as Any)
}
}
说明:调用jsonArrayToModel(_ jsonArrayStr:String, _ modelType:HandyJSON.Type)
传入两个参数,第一个参数是要转换的数组型Json
字符串,第二个参数是要转换的model
类的class
,返回值是一个数组,因为公共类中统一返回的都是BaseModel
类型,所以这里要调用as!
转换成具体的子类类型数组。
3 字典转模型
import UIKit
class JsonToModel: BaseModel {
var id :Int!
var color:String?
var name:String?
}
//字典转模型
fileprivate func dicToModel() {
var dict = [String: Any]()
dict["id"] = 1.1
dict["color"] = "hello"
dict["name"] = "李四"
let model:JsonToModel = JsonUtil.dictionaryToModel(dict,JsonToModel.self) as! JsonToModel
print(model.name as Any)
print(model.color as Any)
print(model.id as Any)
}
说明:调用dictionaryToModel(_ dictionStr:[String:Any],_ modelType:HandyJSON.Type)
,传入两个参数,第一个参数是要转换的字典对象,第二个参数是要转换的model
类的class
,因为公共类中统一返回的都是BaseModel
类型,所以这里要调用as!
转换成具体的子类类型。
4. 模型转Json
JsonToModel.swift
import UIKit
class JsonToModel: BaseModel {
var id :Int!
var color:String?
var name:String?
}
//模型转json
fileprivate func modelToJson() {
let model:JsonToModel = JsonToModel()
model.color = "red"
model.id = 100
model.name = "李四真"
let modelTostring = JsonUtil.modelToJson(model)
print(modelTostring)
}
说明:调用modelToJson(_ model:BaseModel?)
,传入一个参数,传入一个module
对象,返回值是一个JSON
字符串
5. 模型转字典
JsonToModel.swift
import UIKit
class JsonToModel: BaseModel {
var id :Int!
var color:String?
var name:String?
}
//模型转字典
fileprivate func modelTodiction() {
let model:JsonToModel = JsonToModel()
model.color = "red"
model.id = 100
model.name = "李四"
let modelTostring = JsonUtil.modelToDictionary(model)
print(modelTostring["name"] as Any)
}
说明:调用modelToDictionary(_ model:BaseModel?)
传入一个参数,传入一个module
对象,返回值是一个字典对象,对于日常开发中,有时候后台只返回一个字段,比如返回一个成功信息字段,直接把返回的json
串转换成一个字典即可,没必要再构建一个model
去转换。
6. json与嵌套的模型相互转换
CombineModel.swift
import UIKit
class Composition: BaseModel {
var aInt:Int?
var aString:String?
}
class CombineModel: BaseModel {
var aInt:Int?
var comp1:Composition?
var comp2:[Composition] = []
}
//json与嵌套的模型相互转换
fileprivate func jsonTocombilModel() {
let model:CombineModel = CombineModel()
model.aInt = 1001
let posModel1 = Composition()
posModel1.aInt = 1
posModel1.aString = "赵六1"
let posModel2 = Composition()
posModel2.aInt = 2
posModel2.aString = "赵六2"
let posModel3 = Composition()
posModel3.aInt = 3
posModel3.aString = "赵六3"
model.comp1 = posModel1
model.comp2.append(posModel2)
model.comp2.append(posModel3)
let modeString = JsonUtil.modelToJson(model)
print(modeString)
let model2 = JsonUtil.jsonToModel(modeString, CombineModel.self)
print(model2)
}
说明:还是调用Json转模型,模型转Json的方法
,本例子演示的是对象嵌套,对象里面可以嵌套对象,可以嵌套对象数组,平时我们开发经常遇到这种结构的Json串
。
7. 特殊类型字段转换,日期类型,数字类型,颜色
SpacialTypeModel.swift
import UIKit
import HandyJSON
class SpacialTypeModel: BaseModel {
var date: Date?
var decimal: NSDecimalNumber?
var url: URL?
var data: Data?
var color: UIColor?
override func mapping(mapper: HelpingMapper) {
mapper <<<
date <-- CustomDateFormatTransform(formatString: "yyyy-MM-dd")
mapper <<<
decimal <-- NSDecimalNumberTransform()
mapper <<<
url <-- URLTransform(shouldEncodeURLString: false)
mapper <<<
data <-- DataTransform()
mapper <<<
color <-- HexColorTransform()
}
}
// 特殊类型字段转换,日期类型,数字类型,颜色
fileprivate func jsonToSpecialModel () {
let object = SpacialTypeModel()
object.date = Date()
object.decimal = NSDecimalNumber(string: "1.23423414371298437124391243")
object.url = URL(string: "https://www.aliyun.com")
object.data = Data(base64Encoded: "aGVsbG8sIHdvcmxkIQ==")
object.color = UIColor.blue
let specailModelString = JsonUtil.modelToJson(object)
print(object.toJSONString()!)
// it prints:
// {"date":"2017-09-11","decimal":"1.23423414371298437124391243","url":"https:\/\/www.aliyun.com","data":"aGVsbG8sIHdvcmxkIQ==","color":"0000FF"}
let mappedObject:SpacialTypeModel = JsonUtil.jsonToModel(specailModelString, SpacialTypeModel.self) as! SpacialTypeModel
print(mappedObject.date as Any)
}
说明:本例演示的是对于对象里含有特殊类型字段的转换方法,主要注意点在构建model
类里,我们要重写父类mapping
方法还要引入HandyJSON
头文件
五 项目使用示例
// MARK: - 基类模型转模型为返回类型为[String:Any]
public struct DailyStudyBaseModel<T>:HandyJSON {
public var code: Int?
public var msg: String?
public var msgDetail: String?
public var data: T?
public init() {
}
}
// MARK: - 基类模型转模型为返回类型为[[String:Any]]
public struct DailyStudyBaseListModel<T>:HandyJSON {
public var code: Int?
public var msg: String?
public var msgDetail: String?
public var data: [T]?
public init() {
}
}
// MARK: - 基类模型转模型为返回类型为bool 或者是 其他的
public struct DailyStudyBaseResultModel:HandyJSON {
public var code: Int?
public var msg: String?
public var msgDetail: String?
public var data: Any?
public init() {
}
}
// MARK: - 处理分页查询返回的模型
public struct SDBasePageModel<T:HandyJSON>: HandyJSON {
public var pageNum: Int?
public var hasNextPage: Bool?
public var list :[T]?
public init() {
}
}
import Foundation
import SDBasicProject
let width = (SDJG_ScreenWidth - 20 - 18 - 18 - 40) / 3
class JHAdressModel: HandyJSON {
var title : String = ""
var list: [JHAdressCityModel] = []
required init() {
}
}
class JHAdressCityModel: HandyJSON {
var c_province : String = ""
var c_pinyin : String = ""
var c_code : String = ""
var selected: Bool = false
// var label : String = ""
var value : String = ""
var height: CGFloat = 0.0
required init() {
}
var label: String? {
didSet{
let liveNameHeight = self.label?.extGetHeightByWidth(with: self.label ?? "" , width: width, attributes: [NSAttributedString.Key.font : UIFont.systemFont(ofSize: SDAuRate(value: 17), weight: .medium)])
self.height = 8 + (liveNameHeight ?? 0) + 8
}
}
}
//赋值
public var model: JHAdressCityModel? {
didSet{
nameLabel.text = model?.label ?? ""
if model?.label?.isEmpty == true{
self.layer.borderColor = UIColor.clear.cgColor
self.backgroundColor = .clear
self.isUserInteractionEnabled = false
}else{
self.isUserInteractionEnabled = true
if model?.selected == true {
nameLabel.textColor = .extColorWithHex("#E72026")
self.backgroundColor = .extColorWithHex("#FFE3E1")
self.layer.borderColor = UIColor.extColorWithHex("#E72227").cgColor
}else{
nameLabel.textColor = .extColorWithHex("#333333")
self.backgroundColor = .extColorWithHex("#F7F7F7")
self.layer.borderColor = UIColor.extColorWithHex("#F7F7F7").cgColor
}
}
}
}
//
// JHGoldMoldel.swift
// SDHuaYangFriendProject
//
// Created by JH on 2023/1/10.
//
import Foundation
import SDBasicProject
class JHGoldMoldel: HandyJSON {
var creditNum: String? //当前金币数量
// 列表数据
var productList: [JHGoldProductMoldel] = []
required init() {
}
}
class JHGoldProductMoldel: HandyJSON {
var productSkuId: String? //商品ID
var availableCredit: String?//可获得金币
var salePrice:String? //商品价格
var selected: Bool = false
required init() {
}
}
class JHGoldOrderMoldel: HandyJSON {
var orderNo: String? //商品ID
required init() {
}
}
class JHGoldDesMoldel: HandyJSON {
var amount: String?
var createTime: String?
var eventName:String?
var remark: String?
var type: String?
var totalAmount: String?
required init() {
}
}
//
// StationModel.swift
// SDPatternStationProject
//
// Created by lanlan on 2022/3/9.
//
import SDBasicProject
// MARK: - 站长列表
class StationMasterList :HandyJSON {
///小站名称
var siteName:String = ""
///站长名称
var masterName:String = ""
///站长头像
var headImgUrl:String = ""
///站长主键
var id:Int = 0
///是否有直播标记 0: 没有 1:有
var liveFlag:Bool = false
///站长等级 0: 金牌站长
var level:Int = 0
///个人简介
var personalProfile:String = ""
/// 关注数量
var attentionNum:Int = 0
/// 关注数量格式化
var formatAttentionNum:String = ""
/// 点赞数量
var thumbNum:Int = 0
///格式化点赞数量
var formatThumbNum:String = ""
///0: 未置顶 1:置顶
var stickieType:Bool = false
///0:未关注 1:已关注
var attentionType:Bool = false
//默认选中
var isSeleted = false
required init() {
}
func didFinishMapping() {
formatAttentionNum = formatDecimals(num: attentionNum, separate: 10000)
formatThumbNum = formatDecimals(num: thumbNum, separate: 10000)
}
public func formatDecimals(num:Int,separate:Int) -> String {
if num < 10000 {
return "\(num)"
}
let intVal = num / separate
let doubleVal = num % separate
let suffixValue = doubleVal / 1000
if suffixValue == 0 {
return "\(intVal)w+"
}
return "\(intVal).\(suffixValue)w+"
}
}
struct StationMasterDetailModel :HandyJSON {
var course:StationMasterDetailCourseModel?
var groupInfo:StationMasterDetailGroupInfoModel?
//站长信息 本地带的
var siteInfo:StationMasterList?
//关注人数
var memberNum:Int = 0
///关注状态
var attentionType:Bool = false
}
struct StationMasterDetailGroupInfoModel :HandyJSON {
var itemImGroup:[StationMasterDetailGroupModel]?
var publicImGroup:StationMasterDetailGroupModel?
}
struct StationMasterDetailCourseModel :HandyJSON {
var courseFlag:Int = 0
var courseId:String = ""
var coverPic:String = ""
var headImgUrl:String = ""
var lecturerName:String = ""
var liveId:Int = 0
var liveName:String = ""
var liveStartTime:Int = 0
var liveStatus:Int = 0
var siteId:Int = 0
var skuId:Int = 0
var skuName:String = ""
var videoType:Int = 0
}
struct StationMasterDetailGroupModel :HandyJSON {
var imGroupId:String = ""
var imGroupName:String = ""
//0:加锁 1:解锁
var lockStatus:Int = 0
///商城需要的id
var productSpuId:Int = 0
var productSkuId:Int = 0
var siteId:String = ""
var subBrandId:String = ""
var distributeSubBrandId:String = ""
}