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

github repo