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 & Codable
public struct LosslessDefaultStrategy<Value: LosslessStringCodable>{public static var losslessDecodableTypes: [(Decoder) -> LosslessStringCodable?] {@inline(__always)
func decode<T: LosslessStringCodable>(_: 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<Strategy: LosslessDecodingStrategy>: Codable {
private let type: LosslessStringCodable.Type
public var wrappedValue: Strategy.Value
public init(wrappedValue: Strategy.Value) {
self.wrappedValue = 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 = value
self.type = Swift.type(of: rawVal)
return
}
}
throw error
}
}
}
因为上文大量应用范型,
定义,应用默认解码形式 LosslessDefaultStrategy
,的属性装璜器
public typealias LosslessValue<T> = LosslessValueCodable<LosslessDefaultStrategy<T>> 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 = 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 = 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 = try? JSONSerialization.data(withJSONObject: dict, options: []), let model = try? JSONDecoder().decode(Person.self, from: jsonData){print(model.name.strVal, "-", model.age.intVal)
}