ObjMapper
ObjMapper 是基于 Swift 的 Codable 协议扩展的框架,允许您轻松地将模型对象(类和结构)转换为 JSON 并从 JSON 转换回来,而不会产生副作用。
语言:英语|简体中文
功能
- 基于 Codable 的扩展
- 将 JSON 映射到对象
- 对象映射到 JSON
- 嵌套对象
- 支持 nil 对象
- 支持默认值
- 支持数组默认值
- 支持 String,整数,浮点数,Bool 转换
安装
CocoaPods
pod 'ObjMapper'
Swift Package Manager
dependencies: [
.package(url: "https://github.com/ninefivefly/ObjMapper.git", '3.0.0')
]
前言
为什么我们有这个库?
在 Swift 开发中,JSON 数据序列化是一个不可避免的任务。由于 Swift 的类型安全特性,像 JSON 这样的弱类型数据处理一直是个头疼的问题。Swift 4 带来的新特性之一,使人们如释重负。然而,Codable 协议并不能完全满足我们的需求,例如不支持类型的自动转换,也不太友好地支持默认值支持。所以,如果我们解决了这些问题,会是完美无缺的吗?.如何优雅地使用 Codable 协议
教程
1. 在模型和 JSON 之间的转换
// JSON:
{
"uid":888888,
"name": "Tom",
"age": 10
}
// Model:
struct Dog: Codable{
//If the field is not an optional type, use Default and provide a default value, like the following
@Default<Int. Zero> var uid: Int
//If it is an optional type, use Backed
@Backed var name: String?
@Backed var age: Int?
}
//JSON to model
let dog = Dog. decodeJSON(from: json)
//model to json
let json = dog.jsonString
当 JSON/字典中的对象类型与模型属性不一致时,ObjMapper 会自动进行如下转换。不支持自动转换的值将设置为 nil 或默认值。
JSON/字典 | 模型 |
---|---|
字符串 | 字符串、数字类型(包括整数、浮点数)、布尔值 |
数字类型(包括整数、浮点数) | 数字类型、字符串、布尔值 |
布尔值 | 布尔值、字符串、数字类型(包括整数、浮点数) |
nil | nil、0 |
2. 模型嵌套
let raw_json = """
{
"author": {
"id": 888888,
"name": "Alex",
"age": "10"
},
"title": "model and json conversion",
"subTitle":"How to convert gracefully"
}
"""
// Model:
struct Author: Codable{
@Default<Int. Zero> var id: Int
@Default<String. Empty> var name: String
// After using Backed, if the type does not match, the type will be automatically converted
//For example, in the above json, age is a string, and the model we defined is Int,
//Then after declaring @Backed, it will be automatically converted to Int type
@Backed var age: Int?
}
struct Article: Codable {
//If the title in json is nil or does not exist, a default value will be assigned to the title
@Default<String. Empty> var title: String
var subTitle: String?
var author: Author
}
//JSON to model
let article = Article. decodeJSON(from: raw_json)
//model to json
let json = article.jsonString
print(article?.jsonString ?? "")
3. 自定义类型可选值的处理
下面不谈其他的,直接来看代码
struct Activity: Codable {
enum Status: Int {
case start = 1//Activity starts
case processing = 2//Activity in progress
case end = 3//end of event
}
@Default<String. Empty> var name: String
var status: Status//active status
}
这里有一个已经有三个状态的活动,到目前为止一切都很好。有一天,我突然说我需要给活动添加一个已删除的状态,怎么办?
//JSON
{
"name": "New Year's Day Welcome Event",
"status": 4
}
使用 Activity 解析上面的 JSON 会出现错误,我们如何避免,如下所示
var status: Status?
答案是否定的,不是的,不是的,因为可选值的解码表示“如果不存在,设置为 nil”,而不是“如果解码失败,设置为 nil”,然后使用我们的 Default,请查看下面的代码
struct Activity: Codable {
///Step 1: Let Status follow the DefaultValue protocol
enum Status: Int, Codable, DefaultValue {
case start = 1//Activity starts
case processing = 2//Activity in progress
case end = 3//end of event
case unknown = 0//default value, meaningless
///Step 2: Implement the DefaultValue protocol and specify a default value
static func defaultValue() -> Status {
return Status.unknown
}
}
@Default<String. Empty> var name: String
///Step 3: Use Default
@Default<Status> var status: Status//active status
}
//{"name": "New Year's Day Welcome Event", "status": 4 }
//Activity will parse the status into unknown
4. 为常见类型设置不同的默认值
该库内置了许多默认值,例如Int.Zero、Bool.True、String.Empty...,如果我们想为字段设置不同的默认值,请参考以下代码
public extension Int {
enum One: DefaultValue {
static func defaultValue() -> Int {
return 1
}
}
}
struct Dog: Codable{
@Backed var name: String?
@Default<Int. Zero> var uid: Int
//If there is no age field in json or the parsing fails, the age of the model is set to the default value 1
@Default<Int.One> var age: Int
}
5. 数组支持
对于数组,可以使用@Backed和@Default来解决
// JSON:
let raw_json = """
{
"code": 0,
"message": "success",
"data": [{
"name": "New Year's Day Welcome Event",
"status": 4
}]
}
"""
struct Activaty: Codable{
@Default<String. Empty> var name: String
@Default<Int. Zero> var status: Int
}
// If the array is an optional type, you can use @Backed
struct Response1: Codable {
@Default<Int. Zero> var code: Int
@Default<String. Empty> var message: String
@Backed var data: [Activaty]?
}
// For the array, set the default value, if the array does not exist or the parsing error, use the default value
struct Response2: Codable {
@Default<Int. Zero> var code: Int
@Default<String. Empty> var message: String
@Default<Array. Empty> var data: [Activaty]
}
//JSON to model
let rsp1 = Response1. decodeJSON(from: raw_json)
let rsp2 = Response2. decodeJSON(from: raw_json)
//model to json
let json1 = rsp1.jsonString
let json2 = rsp2.jsonString
// print(rsp1?.jsonString ?? "")
// print(rsp2?.jsonString ?? "")
6. 设置通用类型
在开发过程中,我们遇到的第一个JSON可能看起来如下
// JSON:
{
"code": 0,
"message": "success",
"data":[]//This data can be of any type
}
由于数据字段的类型不固定,有时为了统一处理,我们定义以下模型,用枚举类型JsonValue表示。
struct Response: Codable {
var code: Int
var message: String
var data: JsonValue?
}
如果需要获取数据字段的值,可以使用data?.intValue或data?.arrayValue等,具体用法请查看源代码。
注意:这是一个简单的数据模型(如整数、字符串等),可以以半倍的努力实现两倍的结果;如果数据是大型模型,建议指定为特定类型。
7. 如果您是从1.0.x升级到2.0,DefaultValue协议已被修改。如果在之前的代码中使用DefaultValue协议,将报告错误,修改如下
Originally:
///Step 1: Let Status follow the DefaultValue protocol
enum Status: Int, Codable, DefaultValue {
case start = 1//Activity starts
///Step 2: Implement the DefaultValue protocol and specify a default value
static let defaultValue = Status.unknown
}
changed to:
///Step 1: Let Status follow the DefaultValue protocol
enum Status: Int, Codable, DefaultValue {
case start = 1//Activity starts
///Step 2: Implement the DefaultValue protocol and return a default value
static func defaultValue() -> Status {
return Status.unknown
}
}
ps: 如果您不喜欢喷人,请留言如有任何问题 😁😁😁,欢迎 ✨✨✨star✨✨✨ 和PR
作者
许可
ObjMapper基于MIT许可证提供。更多信息请参见LICENSE文件。