ToB企服应用市场:ToB评测及商务社交产业平台

标题: Swift之Codable自定义解析将任意数据类型解析为想要的类型 [打印本页]

作者: 傲渊山岳    时间: 2022-6-24 17:32
标题: Swift之Codable自定义解析将任意数据类型解析为想要的类型
一、前言


二、Codable 自定义解析 Json

① 修改 Key


  1. struct Article: Codable {
  2.     var url: URL
  3.     var title: String
  4.     var body: String
  5. }
复制代码

  1. extension Article {
  2.     enum CodingKeys: String, CodingKey {
  3.         case url = "source_link"
  4.         case title = "content_name"
  5.         case body
  6.     }
  7. }
复制代码

  1. var decoder = JSONDecoder()
  2. decoder.keyDecodingStrategy = .convertFromSnakeCase
复制代码

② 忽略 Key


  1. struct NoteCollection: Codable {
  2.     var name: String
  3.     var notes: [Note]
  4.     var localDrafts = [Note]()
  5. }
复制代码

  1. extension NoteCollection {
  2.     enum CodingKeys: CodingKey {
  3.         case name
  4.         case notes
  5.     }
  6. }
复制代码

③ 创建匹配的结构


  1. {
  2.     "currency": "PLN",
  3.     "rates": {
  4.         "USD": 3.76,
  5.         "EUR": 4.24,
  6.         "SEK": 0.41
  7.     }
  8. }
复制代码

  1. struct CurrencyConversion {
  2.     var currency: Currency
  3.     var exchangeRates: [ExchangeRate]
  4. }
  5. struct ExchangeRate {
  6.     let currency: Currency
  7.     let rate: Double
  8. }
复制代码

  1. private extension ExchangeRate {
  2.     struct List: Decodable {
  3.         let values: [ExchangeRate]
  4.         init(from decoder: Decoder) throws {
  5.             let container = try decoder.singleValueContainer()
  6.             let dictionary = try container.decode([String : Double].self)
  7.             values = dictionary.map { key, value in
  8.                 ExchangeRate(currency: Currency(key), rate: value)
  9.             }
  10.         }
  11.     }
  12. }
复制代码

  1. struct CurrencyConversion: Decodable {
  2.     var currency: Currency
  3.     var exchangeRates: [ExchangeRate] {
  4.         return rates.values
  5.     }
  6.    
  7.     private var rates: ExchangeRate.List
  8. }
复制代码

④ 转换值


  1. protocol StringRepresentable: CustomStringConvertible {
  2.     init?(_ string: String)
  3. }
  4. extension Int: StringRepresentable {}
复制代码

  1. struct StringBacked<Value: StringRepresentable>: Codable {
  2.     var value: Value
  3.    
  4.     init(from decoder: Decoder) throws {
  5.         let container = try decoder.singleValueContainer()
  6.         let string = try container.decode(String.self)
  7.         
  8.         guard let value = Value(string) else {
  9.             throw DecodingError.dataCorruptedError(
  10.                 in: container,
  11.                 debugDescription: "Failed to convert an instance of \(Value.self) from '\(string)'"
  12.             )
  13.         }
  14.         
  15.         self.value = value
  16.     }
  17.    
  18.     func encode(to encoder: Encoder) throws {
  19.         var container = encoder.singleValueContainer()
  20.         try container.encode(value.description)
  21.     }
  22. }
复制代码

  1. struct Video: Codable {
  2.     var title: String
  3.     var description: String
  4.     var url: URL
  5.     var thumbnailImageURL: URL
  6.    
  7.     var numberOfLikes: Int {
  8.         get { return likes.value }
  9.         set { likes.value = newValue }
  10.     }
  11.    
  12.     private var likes: StringBacked<Int>
  13. }
复制代码

三、Codable 将任意类型解析为想要的类型

① 常规解析


  1. {
  2.     "name":"ydw",
  3.     "age":18
  4. }
复制代码

  1. struct User: Codable {
  2.     var name: String
  3.     var age: Int
  4. }
复制代码

② 如果服务器只会以 String 方式返回 Age,同时能确认里面是 Int 还是 Double


  1. protocol StringRepresentable: CustomStringConvertible {
  2.     init?(_ string: String)
  3. }
  4. extension Int: StringRepresentable {}struct StringBacked<Value: StringRepresentable>: Codable {
  5.     var value: Value
  6.    
  7.     init(from decoder: Decoder) throws {
  8.         let container = try decoder.singleValueContainer()
  9.         let string = try container.decode(String.self)
  10.         
  11.         guard let value = Value(string) else {
  12.             throw DecodingError.dataCorruptedError(
  13.                 in: container,
  14.                 debugDescription: "Failed to convert an instance of \(Value.self) from '\(string)'"
  15.             )
  16.         }
  17.         
  18.         self.value = value
  19.     }
  20.    
  21.     func encode(to encoder: Encoder) throws {
  22.         var container = encoder.singleValueContainer()
  23.         try container.encode(value.description)
  24.     }
  25. }
复制代码

  1. {
  2.     "name":"zhy",
  3.     "age":"18"
  4. }
  5. struct User: Codable {
  6.     var name: String
  7.     var ageInt: Int {
  8.         get { return age.value }
  9.         set { age.value = newValue}
  10.     }
  11.     private var age: StringBacked<Int>
  12. }
复制代码
③ 不能确认是什么类型


  1. //  不确定服务器返回什么类型,都转换为 String 然后保证正常解析
  2. //  当前支持 Double Int String
  3. //  其他类型会解析成 nil
  4. //
  5. /// 将 String Int Double 解析为 String? 的包装器
  6. @propertyWrapper public struct YDWString: Codable {
  7.     public var wrappedValue: String?
  8.     public init(from decoder: Decoder) throws {
  9.         let container = try decoder.singleValueContainer()
  10.         var string: String?
  11.         do {
  12.             string = try container.decode(String.self)
  13.         } catch {
  14.             do {
  15.                 try string = String(try container.decode(Int.self))
  16.             } catch {
  17.                 do {
  18.                     try string = String(try container.decode(Double.self))
  19.                 } catch {
  20.                     // 如果不想要 String? 可以在此处给 string 赋值  = “”
  21.                     string = nil
  22.                 }
  23.             }
  24.         }
  25.         wrappedValue = string
  26.     }
  27. }
复制代码

  1. struct User: Codable {
  2.     var name: String
  3.     @YDWString public var age: String?
  4. }
复制代码

  1. struct User: Codable {
  2.     var name: String
  3.     @YDWInt public var age: Int
  4. }
复制代码


免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!




欢迎光临 ToB企服应用市场:ToB评测及商务社交产业平台 (https://dis.qidao123.com/) Powered by Discuz! X3.4