解码多种可能类型的两种技巧(属性包装器)
Swift 的属性包装器是语法糖,
他可以让代码更加的声明式
定义属性的时候,把规则写进去
属性包装器, 主要使用 wrappedValue, 有时候用到 projectedValue问题:
存在这样的一个结构体:
struct Figure: Decodable {
var name: String
var age: Int
}
后端传过来,一个 json,
要求 json 对应的内容,长这样,
能够解析出来
var dict: [String: Any] = ["name": "666", "age": 666]
json 对应的内容,长这样,
也可解析出来
dict = ["name": 666, "age": "666"]
问题,解码一个属性,他的数据可能有多种类型 技巧一,使用属性包装器
提供解码方法
static var losslessDecodableTypes:
, 是一个解码方法的集合系统提供的
LosslessStringConvertible
协议,可以让字符串,转值public typealias LosslessStringCodable = LosslessStringConvertible & Codablepublic struct LosslessDefaultStrategy{
public static var losslessDecodableTypes: [(Decoder) -> LosslessStringCodable?] {
@inline(__always)
func decode(_: T.Type) -> (Decoder) -> LosslessStringCodable? {
return { try? T.init(from: $0) }
}return [
decode(String.self),
decode(Int.self),
decode(Double.self),
decode(Float.self)
]
}
}
通过属性包装器,
- 解码的时候,先使用属性对应类型,进行解码
- 出错了,再使用上面指定的各种类型的解码器,都解码一遍
上面的decode(Float.self)
, 可以删
因为 Double 的精度更好,走不到使用 Float 解码
public protocol LosslessDecodingStrategy {
associatedtype Value: LosslessStringCodable/// An ordered list of decodable scenarios used to infer the encoded type
static var losslessDecodableTypes: [(Decoder) -> LosslessStringCodable?] { get }
}@propertyWrapper
public struct LosslessValueCodable: Codable {
private let type: LosslessStringCodable.Typepublic var wrappedValue: Strategy.Valuepublic init(wrappedValue: Strategy.Value) {
self.wrappedValue = https://www.it610.com/article/wrappedValue
self.type = Strategy.Value.self
}public init(from decoder: Decoder) throws {
do {
self.wrappedValue = try Strategy.Value.init(from: decoder)
self.type = Strategy.Value.self
} catch let error {
for block in Strategy.losslessDecodableTypes{
if let rawVal = block(decoder), let value = Strategy.Value.init("\(rawVal)"){
self.wrappedValue = https://www.it610.com/article/value
self.type = Swift.type(of: rawVal)
return
}
}
throw error
}
}
}
因为上文大量使用范型,
定义,使用默认解码方式
LosslessDefaultStrategy
, 的属性装饰器public typealias LosslessValue = LosslessValueCodable> where T: LosslessStringCodable
调用部分 属性定义
struct Figure: Decodable {
@LosslessValue var name: String
@LosslessValue var age: Int
}
数据解码
var dict: [String: Any] = ["name": "666", "age": 666]
dict = ["name": 666, "age": "666"]
if let jsonData = https://www.it610.com/article/try? JSONSerialization.data(withJSONObject: dict, options: []), let model = try? JSONDecoder().decode(Figure.self, from: jsonData){
print(model.name," - ", model.age)
}
技巧 2 ,糙一些,制定自定义解码
代码: 代码很幼稚,
使用各种类型,去解码,
没有使用范型,使用枚举的多种类型,去获取值
使用值的时候,就将
self
拆包,可能会强转不声明式, 看代码,不知道属性的具体类型
调用的时候,根据业务,去使用对应类型的值
【解码多种可能类型的两种技巧(属性包装器)】属性包装器更加优雅,直接使用,隐藏了 wrappedValue
enum VariousTypeErr: Error {
case miss
}enum VariousType: Decodable{case aDouble(Double), aFloat(Float), aInt(Int), aString(String)init(from decoder: Decoder) throws {if let int = try? decoder.singleValueContainer().decode(Int.self) {
self = .aInt(int)
return
}if let value = https://www.it610.com/article/try? decoder.singleValueContainer().decode(Double.self) {
self = .aDouble(value)
return
}if let gotIt = try? decoder.singleValueContainer().decode(Float.self) {
self = .aFloat(gotIt)
return
}if let text = try? decoder.singleValueContainer().decode(String.self) {
self = .aString(text)
return
}throw VariousTypeErr.miss
}var strVal: String{
switch self {
case .aDouble(let val):
return String(val)
case .aFloat(let val):
return String(val)
case .aInt(let val):
return String(val)
case .aString(let val):
return val
}
}var intVal: Int{
switch self {
case .aDouble(let val):
return Int(val)
case .aFloat(let val):
return Int(val)
case .aInt(let val):
return val
case .aString(let val):
return Int(val) ?? 0
}
}
}
调用:
struct Person: Decodable {
var name: VariousType
var age: VariousType
}var dict: [String: Any] = ["name": "666", "age": 666]
dict = ["name": 666, "age": "666"]if let jsonData = https://www.it610.com/article/try? JSONSerialization.data(withJSONObject: dict, options: []), let model = try? JSONDecoder().decode(Person.self, from: jsonData){
print(model.name.strVal," - ", model.age.intVal)
}
github repo
推荐阅读
- 关于自我为中心的一点感想
- 无故.
- 致每一个追星的女孩(
- 07/22【晨读感悟】保持好奇心,生活才有无限可能
- 你有自己的交友原则吗?
- (If)|(If) 404 Not Found
- 有多少傻瓜在爱着一个不可能的人
- 第三章你如果不能出众就可能出局(下)感悟
- 我可能不会爱你
- 孩子|孩子 我在你身后支持你