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<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 }}@propertyWrapperpublic 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) }