如何使用Codable进行自定义转换?

时间:2018-08-21 14:34:32

标签: ios swift codable

假设我需要将从Web服务收到的日期字符串转换为Date对象。

使用ObjectMapper,很简单:

class Example: Mappable {
    var date: Date?

    required init?(map: Map) { }

    func mapping(map: Map) {  
        date <- (map["date_of_interest"], GenericTransform().dateTransform)
    }
}

我只需要为日期实现一个转换器(在这种情况下为“ GenericTransform”),然后将其作为参数以及要解密的密钥名称传递即可。

现在,使用Codable:

class Example2: Codable {
    var name: String
    var age: Int
    var date: Date?

    enum CodingKeys: String, CodingKey {
        case name, age
        case date = "date_of_interest"
    }
}

根据我的理解,要更改日期,我必须执行以下操作之一:

1)将dateDecodingStrategy传递给我不需要的JSONDecoder,因为我试图将那部分代码保留为通用函数。

2)在示例2内实现一个init(from decoder: Decoder),我也不希望这样做,因为我不得不编写样板代码来解码所有其他属性(否则将自动生成):

init(from decoder: Decoder) throws {
    let container = try decoder.container(keyedBy: CodingKeys.self)
    name = try container.decode(String.self, forKey: .name)
    age = try container.decode(Int.self, forKey: .age)
    let dateString = try container.decode(String.self, forKey: .date)
    let formatter = DateFormatter()
    formatter.dateFormat = "yyyy-MM-dd"
    if let date = formatter.date(from: dateString) {
        self.date = date
    } else {
        //throw error
    }
}

我的问题是:有没有比上面的选项1和2更简单的方法? 也许以某种方式调整CodingKeys枚举?

编辑:

实际上,问题不仅在于日期。在我正在从事的这个项目中,使用ObjectMapper的TransformOf<ObjectType, JSONType>完成了许多自定义转换。

例如,使用以下代码完成从Web服务接收到的十六进制代码到UIColor的颜色转换:

let colorTransform = TransformOf<UIColor, String>(fromJSON: { (value) -> UIColor? in
    if let value = value {
        return UIColor().hexStringToUIColor(hex: value)
    }
    return nil
}, toJSON: { _ in
    return nil
})

我正尝试从项目中删除ObjectMapper,并使用Codable进行这些相同的转换,因此仅使用自定义的dateDecodingStrategy是不够的。

你们会怎么做?为每个必须解码的类实现自定义init(from decoder: Decoder),例如彩色十六进制代码?

1 个答案:

答案 0 :(得分:1)

在您的情况下使用dateDecodingStrategy(因为您仅引用单个日期格式)非常简单……

let decoder = JSONDecoder()
let formatter = DateFormatter()
formatter.dateFormat = "yyyy-MM-dd"
decoder.dateDecodingStrategy = .formatted(formatter)
相关问题