我有一个[String: Bookmark]
字典,但createdAt被保存为Timestamp
,在尝试理解Date
***由于未捕获的异常'NSInvalidArgumentException'而终止应用程序,原因:'JSON写入(__NSDate)中的类型无效'
struct Bookmark: Decodable {
let messageId: String
let messageCreatedAt: Date
}
JSONDecoder().decode([String: Bookmark].self, data: data)
是否有一种方法可以使Swift的Decodable
协议与Firestore时间戳完美配合?
编辑:
如果我打印[String: Any]
,然后尝试像这样在控制台中解码
▿ 1 : 2 elements
- key : "messageCreatedAt"
- value : 2018-11-27 20:59:11 +0000
po valueDict["messageCreatedAt"] as? Date
我明白了
▿ Optional<Date>
▿ some : 2018-11-27 20:59:11 +0000
- timeIntervalSinceReferenceDate : 565045151.531769
因此必须在Decodable
中存在某些内容,才能识别和解析该内容吗?
编辑:
JSON是
{
"messageId": "abc123",
"messageCreatedAt": "2018-11-27 20:59:11 +0000"
}
答案 0 :(得分:1)
JSONDecoder
的解码日期如何由.dateDecodingStrategy
属性的值定义。
如果您必须从字符串中解析Date
,则应使用.iso8601
或.formatted(_:)
(或者,如果您的日期格式确实是自定义的,复杂的和/或很奇怪的,则可能需要使用.custom(_:)
)。
您的日期字符串几乎是ISO 8601
格式的(日期和时间部分之间仅缺少T
),但这足以失败。
因此,您最好的选择是使用formatted(_:)
:
// Declare it somewhere and reuse single instance as much as possible, formatter initialization is quite expensive
let dateFormatter = DateFormatter()
dateFormatter.locale = Locale(identifier: "en_US_POSIX") // Better to fix Locale here
dateFormatter.dateFormat = "yyyy-MM-dd kk:mm:ss Z"
然后
let decoder = JSONDecoder()
decoder.dateDecodingStrategy = .formatted(dateFormatter)
let bookmark = try decoder.decode(Bookmark.self, from: data)
print(bookmark.messageCreatedAt, bookmark.messageCreatedAt.timeIntervalSince1970)
// prints "2018-11-27 20:59:11 +0000 1543352351.0"