import SmartCodable
struct Model: SmartCodable {
var name: String = ""
}
let dict: [String: String] = ["name": "xiaoming"]
guard let model = Model.deserialize(from: dict) else { return }
import SmartCodable
struct Model: SmartCodable {
var name: String = ""
}
let dict: [String: String] = ["name": "xiaoming"]
let arr = [dict, dict]
guard let models = [Model].deserialize(from: arr) else { return }
// to model
guard let xiaoMing = JsonToModel.deserialize(from: dict) else { return }
// to dict
let studentDict = xiaoMing.toDictionary() ?? [:]
// to json
let json1 = xiaoMing.toJSONString(prettyPrint: false) ?? ""
SmartCoable supports deserialization from designated path of JSON.
SmartCoable支持从指定路径的JSON进行反序列化。
let jsonString = """
{
"people": [
{
"name": "John Doe",
"age": 30
},
{
"name": "Jane Smith",
"age": 25
}
]
}
"""
struct PathModel: SmartCodable {
var name: String?
var age: Int?
}
if let models = [PathModel].deserialize(from: jsonString, designatedPath: "people") {
print(models)
}
Notice that all the properties of a class/struct need to deserialized should be type conformed to SmartCodable
.
注意,类/结构体中所有需要反序列化的属性都应该符合 SmartCodable
。
struct Model: SmartCodable {
var name: String = "Mccc"
var sub: SubModel?
}
struct SubModel: SmartCodable {
var name: String = ""
}
Codable does not decode the Any type, meaning that the attribute type of the model cannot be Any, [Any] and [String: Any].
SmartAny is a solution to Any provided by SmartCodable.
Codable是无法解码Any类型的,意味着模型的属性类型不可以是 Any,[Any] 和 [String: Any] 类型。SmartCodable 提供了 SmartAny 来解决改它。
struct AnyModel: SmartCodable {
@SmartAny
var name: Any?
@SmartAny
var dict: [String: Any] = [:]
@SmartAny
var arr: [Any] = []
}
let dict = [
"name": "xiao ming",
"age": 20,
"dict": inDict,
"arr": arr
] as [String : Any]
guard let model = AnyModel.deserialize(from: dict) else { return }
// ❌ 错误的示范
struct Model<T: SmartCodable>: SmartCodable {
@SmartAny
var data: T?
}
struct SubModel: SmartCodable {
var name: String?
}
let dict: [String: Any] = [
"hobby": "{\"name\":\"sleep\"}",
]
guard let model = Model.deserialize(from: dict) else { return }
print(model)
struct Model: SmartCodable {
var hobby: Hobby?
}
struct Hobby: SmartCodable {
var name: String = ""
}
Use SmartColor instead of UIColor.
let dict = [
"color": "7DA5E3"
]
struct Model: SmartCodable {
var color: SmartColor?
}
guard let model = Model.deserialize(from: dict) else { return }
print(model.color?.peel)
UIColor 是
non-final class
。非最终类不能简单地实现Codable
的init(from:)
。
Make the enumeration follow SmartCaseDefaultable.
让枚举遵循 SmartCaseDefaultable。
struct Model: SmartCodable {
var enum: MyEnum?
}
enum myEnum: String, SmartCaseDefaultable {
case a
case b
case c = "hello"
}
Make the enumeration follow SmartAssociatedEnumerable。Override the mappingForValue method and take over the decoding process yourself.
让枚举遵循 SmartAssociatedEnumerable,重写mappingForValue方法,你自己接管解码过程。
enum Sex: SmartAssociatedEnumerable {
case man
case women
case other(String)
}
struct Model: SmartCodable {
var sex: Sex = .man
static func mappingForValue() -> [SmartValueTransformer]? {
[
CodingKeys.sex <--- RelationEnumTranformer()
]
}
}
struct RelationEnumTranformer: ValueTransformable {
typealias Object = Sex
typealias JSON = String
func transformToJSON(_ value: Introduce_8ViewController.Sex?) -> String? {
// do something
}
func transformFromJSON(_ value: Any?) -> Sex? {
// do something
}
}
If attribute resolution fails, SmartCodable performs compatibility processing for thrown exceptions. Ensure that the entire parsing is not interrupted. Even better, you don't have to do anything about it.
某个属性解析失败时候,SmartCodable会接管抛出的异常,进行兼容性处理。确保整个解析不会被中断。更好的是不需要你为此做任何事情。
let dict = [
"number1": "123",
"number2": "Mccc",
"number3": "Mccc"
]
struct Model: SmartCodable {
var number1: Int?
var number2: Int?
var number3: Int = 1
}
// decode result
// Model(number1: 123, number2: nil, number3: 1)
When the data is parsed, the type cannot be matched. Raises a.typeMismatch error. SmartCodable will attempt to convert data of type String to the desired type Int.
当对该数据进行解析时,由于不能匹配类型。会抛出.typeMismatch
error。SmartCodable 会尝试将 String类型的数据 转换为 所需的 Int 类型数据。
When the type conversion fails, the initialization value of the currently parsed property is retrieved for padding.
当类型转换失时,会获取当前解析的属性的初始化值进行填充。
struct Model: SmartCodable {
var name: String = ""
var ignore: String = ""
var age: Int = 0
enum CodingKeys: String, CodingKey {
case name
case age
}
}
If you don't want ignore to participate in parsing, delete it in CodingKeys and you'll be left with parsing. But with SmartCodable, you can use @IgnoredKey.
如果你不希望 ignore 参与解析,就在 CodingKeys 中删除它,留下的就是参与解析的。但有了 SmartCodable
,你就可以使用 @IgnoredKey
.
struct Home: SmartCodable {
var name: String = ""
@IgnoredKey
var age: [Any] = ["1"]
@IgnoredKey
var area: String = "area"
}
public enum SmartKeyDecodingStrategy : Sendable {
case useDefaultKeys
// 蛇形命名转驼峰命名
case fromSnakeCase
// 首字母大写转小写
case firstLetterLower
// 首字母小写转大写
case firstLetterUpper
}
let option1: SmartDecodingOption = .key(.fromSnakeCase)
guard let model1 = TwoModel.deserialize(from: dict1, options: [option1]) else { return }
If you only need to change the mapping rules of a Model Key, you can override mappingForKey
and complete the mapping relationship as required.
如果你只需要修改某个Model的Key的映射规则,可以重写 mappingForKey
, 按照要求完成映射关系。
struct Model: SmartCodable {
var name: String = ""
var age: Int = 0
static func mappingForKey() -> [SmartKeyTransformer]? {
[
CodingKeys.age <--- "person_age"
CodingKeys.name <--- ["nickName", "realName"],
]
}
}
Override 'mappingForKey` to specify the parsing path
重写mappingForKey
可以实现跨层解析。
let dict = [
"age": 10,
"sub": [
"name": "Mccc"
]
]
struct Model: SmartCodable {
var age: Int = 0
var name: String = ""
static func mappingForKey() -> [SmartKeyTransformer]? {
[ CodingKeys.name <--- "sub.name" ]
}
}
SmartDecodingOption provides three decoding options:
SmartDecodingOption提供了三种解码选项,分别为:
public enum SmartDecodingOption {
/// 用于解码 “Date” 值的策略
case dateStrategy(JSONDecoder.DateDecodingStrategy)
/// 用于解码 “Data” 值的策略
case dataStrategy(JSONDecoder.DataDecodingStrategy)
/// 用于不符合json的浮点值(IEEE 754无穷大和NaN)的策略
case floatStrategy(JSONDecoder.NonConformingFloatDecodingStrategy)
}
- Date
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "yyyy-MM-dd HH:mm:ss"
let option: JSONDecoder.SmartDecodingOption = .dateStrategy(.formatted(dateFormatter))
guard let model = FeedOne.deserialize(from: json, options: [option]) else { return }
- Data
let option: JSONDecoder.SmartDecodingOption = .dataStrategy(.base64)
guard let model = FeedOne.deserialize(from: json, options: [option]) else { return }
gurad let data = model.address, let url = String(data: data, encoding: .utf8) { else }
- Float
let option: JSONDecoder.SmartDecodingOption = .floatStrategy(.convertFromString(positiveInfinity: "infinity", negativeInfinity: "-infinity", nan: "NaN"))
guard let model1 = FeedOne.deserialize(from: json, options: [option]) else { return }
If you want to control the scope of influence, you can override mappingForValue
to give each attribute a different parsing policy.
如果你想控制影响范围,可以重写 mappingForValue
,给每个属性设置不同的解析策略。
struct SmartModel: SmartCodable {
var date1: Date?
var date2: Date?
var url: URL?
var data: Data?
static func mappingForValue() -> [SmartValueTransformer]? {
let format = DateFormatter()
format.dateFormat = "yyyy-MM-dd"
return [
CodingKeys.url <--- SmartURLTransformer(prefix: "https://"),
CodingKeys.date2 <--- SmartDateTransformer(),
CodingKeys.date1 <--- SmartDateFormatTransformer(format),
CodingKeys.data <--- SmartDataTransformer()
]
}
}
If you need additional parsing rules, Transformer will implement them yourself. Follow ValueTransformable to implement the requirements of the protocol.
如果你需要额外的解析规则,Transformer 交给你自己实现。请遵循 ValueTransformable,实现协议的相关要求。
public protocol ValueTransformable {
associatedtype Object
associatedtype JSON
/// transform from ’json‘ to ’object‘
func transformFromJSON(_ value: Any?) -> Object?
/// transform to ‘json’ from ‘object’
func transformToJSON(_ value: Object?) -> JSON?
}
When decoding is complete, didFinishMapping is called. You can rewrite it.
当解码完成时,调用 didFinishMapping。你可以重写它。
class Model: SmartDecodable {
var name: String = ""
var age: Int = 0
var desc: String = ""
required init() { }
func didFinishMapping() {
if name.isEmpty {
name = "-"
}
}
}
Inheritance does not have a particularly good implementation in Codable, but SmartCodable provides a combination (@SmartFlat) that indirectly implements inheritance requirements.
继承在Codable中没有特别好的实现方案, SmartCodable提供了组合方式(@SmartFlat)用来间接实现继承的需求。
let jsonString = """
{
"a": "aa",
"b": 100,
"longitude": 3,
"latitude": 4
}
"""
if let model = SubModel.deserialize(from: jsonString) {
smartPrint(value: model.c)
}
struct SuperModel: SmartCodable {
var longitude: Double?
var latitude: Double?
}
struct SubModel: SmartCodable {
var a: String?
var b: Int?
@SmartFlat
var c: SuperModel?
}
struct Model: SmartCodable {
var name: String = ""
var age: Int = 0
}
var dic1: [String : Any] = [
"name": "mccc",
"age": 10
]
let dic2: [String : Any] = [
"age": 200
]
guard var model = Model.deserialize(from: dic1) else { return }
SmartUpdater.update(&model, from: dic2)
// now: model is ["name": mccc, "age": 200].
It can accommodate any data structure, including nested array structures.
它可以适应任何数据结构,包括嵌套的数组结构。