Codable in swift

130 阅读2分钟

Codable是swift4.0中的一个特性,它是由EncodableDecodable两个协议组成的:

public typealias Codable = Decodable & Encodable

Encodable这个协议用在那些需要被编码的数据类型上。如果遵循了这个协议,并且这个类的所有属性都是Encodable的话,编辑器就会自动对该数据类型进行编码操作。

Decodable这个协议用在那些需要被解码的数据类型上。如果遵循了这个协议,那么编辑器则会自动对该数据类型进行解码操作

下来我们用一个例子来展示一下Codable的使用:

let json = """
    {
        "name": "codable",
        "age": 22,
        "desc": "data analysis framework in swift"
    }
"""
/// 建立模型
struct Coda : Codable {
  var name: String?
  var age: Int?
  var desc: String?
}


/// JSON 转换为Model
let decoder = JSONDecoder()
// 数组模型转化  (注意:先将json字符串转为data)
let products = try decoder.decode(Coda.self, from: json.data(using:.utf8)!)

如果后台返回的Json数据结构比较复杂的话,比如我们可以在struct中再嵌套一个struct来建立模型,同时新建立的模型也必须遵循Codable协议。

但是有时候后台的命名与我们前端创建的不一致,这个时候我们就需要采用映射机制来解决这个问题了。这里列出两种解决方案: 方案一:采用CodingKey协议,进行枚举映射

/// 只需修改模型,实现CodingKey协议
struct Coda : Codable {
  var name: String
  var age: Int
  var desc: String
  
  /// 自定义字段属性
  /// 注意 1.需要遵守Codingkey  2.每个字段都要枚举
   private enum CodingKeys: String, CodingKey {
       case name = "_name"
       case age 
       case desc
    }
}

方案二:通过DecoderkeyDecodingStrategy属性,将属性的值设置为convertFromSnakeCase,这样我们就不需要额外的代码处理了

/// 只需增加一行代码
let decoder = JSONDecoder()
// 编码策略  使用从蛇形转化为大写 encode时同样也可将驼峰命名法转化为下划线
decoder.keyDecodingStrategy = .convertFromSnakeCase  
let products = try decoder.decode(Coda.self, from: json.data(using:.utf8)!)

keyDecodingStrategy是一个枚举值,他还提供了自定义转化规则

 public enum KeyDecodingStrategy {
        case useDefaultKeys
        case convertFromSnakeCase
        case custom(([CodingKey]) -> CodingKey) //自定义转化规则
  }
let json = """
    {
        "_name": "Codable",
        "age": 200,
        "desc": "data analysis framework in swift"
    }
"""
 let decoder = JSONDecoder()
// 自定义转化规则
 decoder.keyDecodingStrategy = .custom({ (keys) -> CodingKey in
             let lastKey = keys.last!
             guard lastKey.intValue == nil else { return lastKey }
             // 将首字母大写的转化为小写的
             let stringValue = lastKey.stringValue.prefix(1).lowercased()    +lastKey.stringValue.dropFirst()
             return AnyKey(stringValue: stringValue)!
  })