如何将DateFormatter烘焙到Swift结构中,以便我不需要告诉JSONDecoder?

时间:2018-04-28 11:00:55

标签: swift jsondecoder

我正在使用Swift 4解码来自Twitter的一些JSON:

struct Tweet: Codable {

    let id: String
    let createdAt: Date
    let text: String

    enum CodingKeys: String, CodingKey {
        case id = "id_str"
        case createdAt = "created_at"
        case text
    }
}

let decoder = JSONDecoder()

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "eee MMM dd HH:mm:ss ZZZZ yyyy"
decoder.dateDecodingStrategy = .formatted(dateFormatter)

let tweets = try decoder.decode([Tweet].self, from: data!)

如何制作,以便我的代码不必记住设置decoder.dateDecodingStrategy。理想情况下,Tweet结构将知道其日期格式,并将dateFormatter常量静态成员变量初始化为正确的格式。

我想我需要在init(decoder: Decoder)以某种方式使用Tweet,但我不确定如何。

2 个答案:

答案 0 :(得分:1)

正如@Larme在评论中所建议的那样,您可以继承JSONDecoder并覆盖其init方法,您可以将dateDecodingStrategy设置为Twitter的日期格式。您还应该确保正确设置locale的{​​{1}},否则它无法正确解码日/月名称。我认为这些都是英文版,因此我建议您使用DateFormatter Locale作为硬编码日期格式。

en_US_POSIX

然后,您只需在解码响应时初始化class JSONTweetDecoder: JSONDecoder { private static let dateFormatter: DateFormatter = { let dateFormatter = DateFormatter() dateFormatter.dateFormat = "eee MMM dd HH:mm:ss ZZZZ yyyy" dateFormatter.locale = Locale(identifier: "en_US_POSIX") return dateFormatter }() override init() { super.init() self.dateDecodingStrategy = .formatted(JSONTweetDecoder.dateFormatter) } } 而不是JSONTweetDecoder

JSONDecoder

答案 1 :(得分:0)

您可以扩展Formatter并创建自定义静态DateFormatter。

extension Formatter {
    static let custom: DateFormatter = {
        let formatter = DateFormatter()
        formatter.locale = Locale(identifier: "en_US_POSIX")
        formatter.dateFormat = "eee MMM dd HH:mm:ss ZZZZ yyyy"
        return formatter
    }()
}

如果您想让Tweet解析您的日期字符串,您可以提供自己的自定义解码器初始化程序,如下所示:

extension Tweet {
    public init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        id = try container.decode(String.self, forKey: .id)
        text = try container.decode(String.self, forKey: .text)
        createdAt = try Formatter.custom.date(from: container.decode(String.self, forKey: .createdAt))!
    }
}

这假设您的日期字符串格式正确,如果您的日期字符串不能保证格式正确,您可以使Date属性可选,并从日期(from:String)方法中删除强制解包。