-1

我正在使用 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!)

我怎样才能做到这一点,这样我的代码就不必一直记住 set decoder.dateDecodingStrategy。理想情况下,该Tweet结构将通过dateFormatter初始化为正确格式的常量静态成员变量来了解其日期格式。

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

4

2 回答 2

1

正如@Larme 在评论中所建议的那样,您可以子类化JSONDecoder并覆盖init您将其设置dateDecodingStrategy为 Twitter 日期格式的方法。您还应该确保正确设置localeDateFormatter否则将无法正确解码日/月名称。我假设这些是英文的,所以我建议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)
    }
}

然后你只需要在解码响应时初始化 aJSONTweetDecoder而不是 a 。JSONDecoder

let tweets = try JSONTweetDecoder().decode([Tweet].self, from: data!)
于 2018-04-28T11:24:21.247 回答
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 属性可选并从 date(from: String) 方法中删除强制展开。

于 2018-04-28T11:50:26.700 回答