ObjMapper 3.0.0

ObjMapper 3.0.0

JIANGPENGCHENG 维护。



ObjMapper 3.0.0

  • JIANG PENG CHENG

ObjMapper

Version License Platform

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

作者

姜鹏诚,[email protected]

许可

ObjMapper基于MIT许可证提供。更多信息请参见LICENSE文件。