HollowCodable
HollowCodable 是一个基于Swift使用属性包装器的对Codable协议进行扩展的框架。
- 使用属性包装器使复杂的可编码序列化变得轻而易举!
原生 JSON Codable 的问题
- 不支持自定义某个属性的 coding key,一旦你有这种需求,要么把所有的 coding key 手动实现一遍去修改想要的 coding key,要么就得在 decode 的时候去设置 Decoder,极其不方便。
- 不支持忽略掉某些不能 Codable 的属性, 还是需要手动实现 coding key 才行。
- 解码的时候不支持多个 coding key 映射同一个属性,以及蛇形转驼峰等。
- 不能使用模型的默认值,当 decode 的数据缺失时无法使用定义里的默认值而是 throw 数据缺失错误,这很明显是不合理的。
- 不支持简单的类型转换,比如转换 0/1 到 false/true,"123" 到 Int的123 或者反过来,谁又能确保服务端的人员不会失手修改了字段类型导致 app 端故障呢?
- 支持Any属性,很多时候首页模型会包含很多子模型,但是子模型又都不一样,这时就需要解析成Any,然后根据模块去确认子模型。
ok, 以上问题在你使用HollowCodable之后统统可以得到解决,不用谢!
特性
-
基于Codable的扩展,采用属性包装器设计
-
支持属性键名称修改和多键映射到同一属性
-
JSON映射为Model,Model映射为JSON
-
支持嵌套对象,支持Any对象
-
支持nil对象
-
支持默认值,数组、字典默认值
-
支持String和整数、浮点数、Bool之间的转换
-
支持自定义解码器和编码器
-
Immutable: 通过属性包装使其变成只读属性,它可以与其他编码一起使用。
struct YourModel: HollowCodable {
@Immutable
var id: Int
@Immutable @BoolCoding
var bar: Bool?
}
- IgnoredKey: 将此属性添加到可选属性中,以便在编码或解码时不包含它。
struct YourModel: HollowCodable {
@IgnoredKey
var ignorKey: String? = "Condy" // 相当于使用 `lazy`.
lazy var ignorKey2: String? = "Coi"
}
- DefaultBacked: 为常见类型设置不同的默认值。
- 这个库内置了许多默认值,如Int, Bool, String, Array...
- 如果我们想为该字段设置不同的默认值。
struct YourModel: HollowCodable {
@DefaultBacked<Int>
var val: Int // 如果该字段不是可选的,则默认为0。
@DefaultBacked<Bool>
var boo: Bool // 如果该字段不是可选的,则默认为false。
@DefaultBacked<String>
var string: String // 如果该字段不是可选的,则默认为""。
@DefaultBacked<AnyDictionary>
var list: [String: Any] // 如果该字段不是可选的,则默认为[:]。
}
UIColor/NSColor
- HexColorCoding: 将十六进制字符串颜色转化为UIColor/NSColor属性包装器。
- 支持十六进制字符串颜色格式有
#RGB
、#RGBA
、#RRGGBB
、#RRGGBBAA
- 支持十六进制字符串颜色格式有
- RGBColorCoding: 将Red、Green、Blue颜色转化为UIColor/NSColor属性包装器。
- RGBAColorCoding: 将Red、Green、Blue和Alpha颜色转化为UIColor/NSColor属性包装器。
struct YourModel: HollowCodable {
@HexColorCoding
var color: HollowColor?
@RGBColorCoding
var background_color: HollowColor?
}
Bool
- BoolCoding: 支持使用
Bool
,Int
或String
来表示布尔值。- 大于0则转化为true,小于等于0则转化为false。
- 这些数据 "true"/"yes"/"y"/"t"/"1"/">0" 则转为true,
- 这些数据 "false"/"no"/"f"/"n"/"0" 则转为false.
- FalseBoolCoding: 如果字段不是可选类型,则默认为false。
- TrueBoolCoding: 如果字段不是可选类型,则默认为true。
struct YourModel: HollowCodable {
@Immutable @BoolCoding
var bar: Bool?
@FalseBoolCoding
var hasD: Bool
@TrueBoolCoding
var hasT: Bool
}
Data
- Base64Coding: 对于应序列化为Base64编码字符串的Data属性。
struct YourModel: HollowCodable {
@Base64Coding
var base64Data: Data?
}
您可以自定义您自己的数据(反)序列化类型DataValue.
例如:
public enum YourData: DataConverter {
public typealias Value = String
public typealias FromValue = Data
public typealias ToValue = String
public static let hasValue: Value = ""
public static func transformToValue(with value: FromValue) -> ToValue? {
// data to string..
}
public static func transformFromValue(with value: ToValue) -> FromValue? {
// string to data..
}
}
Used:
struct YourModel: HollowCodable {
AnyBacked<DataValue<YourData>>
var data: Data?
}
Date
- ISO8601DateCoding: 将
String
或TimeInterval
值解码为ISO8601日期。 - RFC2822DateCoding: 将
String
或TimeInterval
值解码为RFC2822日期。 - RFC3339DateCoding: 将
String
或TimeInterval
值解码为RFC3339日期。
struct YourModel: HollowCodable {
@ISO8601DateCoding
var iso8601: Date? // 现在解码到ISO8601日期。
@RFC2822DateCoding
var data1: Date? // 现在解码到RFC2822日期。
@RFC3339DateCoding
var data2: Date? // 现在解码到RFC3339日期。
}
- SecondsSince1970DateCoding: 对于应该序列化为SecondsSince1970的Date时间戳属性。
- MillisecondsSince1970DateCoding: 对于应该被序列化为msecondssince1970的Date时间戳属性。
struct YourModel: HollowCodable {
@SecondsSince1970DateCoding
var timestamp: Date // 现在编码为SecondsSince1970
@MillisecondsSince1970DateCoding
var timestamp2: Date // 现在编码为MillisecondsSince1970
}
支持使用不同格式的(反)序列化,例如:
struct YourModel: HollowCodable {
@DateCoding<Hollow.DateFormat.yyyy_mm_dd, Hollow.Timestamp.secondsSince1970>
var time: Date? // 解码使用`yyyy-MM-dd`格式和编码使用`seconds`时间戳。
}
Enum
- EnumCoding: 要实现可转换,enum必须符合rawrepresable协议。现在没有什么特别需要做的。
struct YourModel: HollowCodable {
@EnumCoding<AnimalType>
var animal: AnimalType? //
}
enum AnimalType: String {
case Cat = "cat"
case Dog = "dog"
case Bird = "bird"
}
NSDecimalNumber
- NSDecimalNumberCoding: 可以将
String
、Double
、Float
、CGFloat
、Int
orInt64
解码成NSDecimalNumber属性.
struct YourModel: HollowCodable {
@DecimalNumberCoding
var amount: NSDecimalNumber?
}
AnyDictionary/AnyDictionaryArray
- DictionaryCoding: 支持任何
[String:Any]
带有字典的值属性包装器。 - ArrayCoding: 支持任何值
[String:Any]
字典属性包装与数组。
"mixDict": {
"sub": {
"amount": "52.9",
},
"array": [{
"val": 718,
}, {
"val": 911,
}],
"opt": null
}
struct YourModel: HollowCodable {
@AnyBacked<AnyDictionary>
var mixDict: [String: Any]? // 嵌套支持。
@AnyBacked<AnyDictionaryArray>
var mixLiat: [[String: Any]]?
}
AnyX
- AnyXCoding: 支持设置任意类型
Any
。
struct YourModel: HollowCodable {
@AnyBacked<AnyX>
var x: Any? // Also nested support.
}
JSON
- 支持直接解码网络请求响应数据。
{
"code": 200,
"message": "test case.",
"data": [{
"id": 2,
"title": "Harbeth Framework",
"github": "https://github.com/yangKJ/Harbeth",
"amount": "23.6",
"hex_color": "#FA6D5B",
"type": "text1",
"timestamp" : 590277534,
"bar": 1,
"hasDefBool": 2,
"time": "2024-05-29 23:49:55",
"iso8601": null,
"anyString": 5,
"background_color": {
"red": 255,
"green": 128,
"blue": 128
},
"dict": {
"amount": "326.0"
},
"mixDict": {
"sub": {
"amount": "52.9",
},
"array": [{
"val": 718,
}, {
"val": 911,
}]
},
"list": [{
"fruit": "Apple",
"dream": null
}, {
"fruit": "Banana",
"dream": "Night"
}]
}, {
"id": 7,
"title": "Network Framework",
"github": "https://github.com/yangKJ/RxNetworks",
"amount": 120.3,
"hex_color2": "#1AC756",
"type": null,
"timestamp" : 590288534,
"bar": null,
"hasDefBool": null,
"time": "2024-05-29 20:23:46",
"iso8601": "2023-05-23T09:43:38Z",
"anyString": null,
"background_color": null,
"dict": null,
"mixDict": null,
"list": null
}]
}
- 使用如下:
let datas = ApiResponse<[YourModel]>.deserialize(from: json)?.data
- Model和JSON互相转换。
json = """
{
"uid":888888,
"name": "Condy",
"age": 18
}
"""
struct YourModel: HollowCodable {
@Immutable
var uid: Int?
@DefaultBacked<Int>
var age: Int // 如果非可选字段,则为0。
@AnyBacked<String>
var named: String? // 支持多键。
static var codingKeys: [ReplaceKeys] {
return [
ReplaceKeys(location: CodingKeys.named, keys: "name", "named"),
]
}
}
// JSON to Model.
let model = YourModel.deserialize(from: json)
// Model to JSON
let json = model.toJSONString(prettyPrint: true)
属性包装器
- @Immutable: 将属性变成只读。
- @IgnoredKey: 序列化/反序列化时将忽略的字段。
- @AnyBacked: 支持多种类型的属性包装器。
- @DefaultBacked: 解码失败时,将设置默认值。
- @BoolCoding: 布尔值类型的属性包装器。
- @Base64DataCoding: Base64Data属性包装器。
- @DateFormatterCoding: 支持自定义日期格式的属性包装器。
- @ISO8601DateCoding: ISO8601日期属性包装器。
- @TimestampDateCoding: 时间戳属性包装器。
- @DecimalNumberCoding: NSDecimalNumber属性包装器。
- @EnumCoding: 枚举属性包装器。
- @HexColorCoding: Hex与Color属性包装器。
- @RGBAColorCoding: RGBA与Color属性包装器。
- @PointCoding: CGPoint属性包装器。
- @RectCoding: CGRect属性包装器。
这边也支持用户自定义,你只需要实现Transformer协议即可。
它还支持可以设置默认值的属性包装器,您需要实现HasDefaultValuable协议即可。
Booming
Booming 是Swift的基础网络库。它是为Swift 5开发的,旨在利用最新的语言特性。该框架的最终目标是实现简单的网络连接,从而使编写易于维护的代码变得容易。
是一套网络架构,基于Moya插件设计使用。
这个模块是序列化和反序列化数据,取代HandyJSON。
🎷 结合网络接口使用如下:
func request(_ count: Int) -> Observable<[CodableModel]> {
CodableAPI.cache(count)
.request(callbackQueue: DispatchQueue(label: "request.codable"))
.deserialized(ApiResponse<[CodableModel]>.self)
.compactMap({ $0.data })
.observe(on: MainScheduler.instance)
.catchAndReturn([])
}
- RxSwift Codable 扩展。
public extension Observable where Element: Any {
@discardableResult func deserialized<T>(_ type: T.Type) -> Observable<T> where T: HollowCodable {
return self.map { element -> T in
return try T.deserialize(element: element)
}
}
@discardableResult func deserialized<T>(_ type: [T].Type) -> Observable<[T]> where T: HollowCodable {
return self.map { element -> [T] in
return try [T].deserialize(element: element)
}
}
@discardableResult func deserialized<T>(_ type: T.Type) -> Observable<ApiResponse<T.DataType>> where T: HasResponsable, T.DataType: HollowCodable {
return self.map { element -> ApiResponse<T.DataType> in
return try T.deserialize(element: element)
}
}
@discardableResult func deserialized<T>(_ type: T.Type) -> Observable<ApiResponse<[T.DataType.Element]>> where T: HasResponsable, T.DataType: Collection, T.DataType.Element: HollowCodable {
return self.map { element -> ApiResponse<[T.DataType.Element]> in
return try T.deserialize(element: element)
}
}
}
最后
- 关于Codable框架介绍与设计到此为止吧。
- 慢慢再补充其他相关属性包装器,喜欢就给我点个星🌟吧。
- Demo地址,目前包含
20+
种属性包装器。 - 再附上一个图像滤镜库HabethDemo地址 🎷喜欢的老板们可以点个星🌟
✌️.