gpt4 book ai didi

swift - JSONEncoder 的 dateEncodingStrategy 不工作

转载 作者:可可西里 更新时间:2023-10-31 23:57:28 25 4
gpt4 key购买 nike

我正在尝试使用 Swift 4 的 Encodable+JSONEncoder 将结构序列化为字符串。该对象可以保存异构值,如 String、Array、Date、Int 等。

除了 Date 之外,使用的方法工作正常。JSONEncoder 的 dateEncodingStrategy 属性没有任何效果。

这是一个在 Playground 中重现行为的片段:

struct EncodableValue:Encodable {
var value: Encodable

init(_ value: Encodable) {
self.value = value
}

func encode(to encoder: Encoder) throws {
try value.encode(to: encoder)
}
}

struct Bar: Encodable, CustomStringConvertible {
let key: String?
let value: EncodableValue?

var description: String {
let encoder = JSONEncoder()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "E, d MMM yyyy"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
encoder.dateEncodingStrategy = .formatted(dateFormatter)
let jsonData = try? encoder.encode(self)
return String(data: jsonData!, encoding: .utf8)!
}
}

let bar1 = Bar(key: "bar1", value: EncodableValue("12345"))
let bar2 = Bar(key: "bar2", value: EncodableValue(12345))
let bar3 = Bar(key: "bar3", value: EncodableValue(Date()))

print(String(describing: bar1))
print(String(describing: bar2))
print(String(describing: bar3))

输出:

"{"key":"bar1","value":"12345"}\n"
"{"key":"bar2","value":12345}\n"
"{"key":"bar3","value":539682026.06086397}\n"

对于 bar3 对象:我期待类似 "{"key":"bar3","value":"Thurs, 3 Jan 1991"}\n" 的结果,但它返回默认 .deferToDate 策略格式的日期。

##编辑 1##

所以我在 XCode 9 中运行了相同的代码,它给出了预期的输出,即将日期正确格式化为字符串。我认为 9.2 对 Swift 4 进行了小幅升级,这会破坏此功能。不确定下一步该做什么。

##编辑 2##

作为临时补救措施,在更改为使用闭包的@Hamish 方法之前,我使用了以下代码段。

struct EncodableValue:Encodable {
var value: Encodable

init(_ value: Encodable) {
self.value = value
}

func encode(to encoder: Encoder) throws {
if let date = value as? Date {
var container = encoder.singleValueContainer()
try container.encode(date)
}
else {
try value.encode(to: encoder)
}

}
}

最佳答案

使用自定义日期编码策略时,编码器intercepts calls编码 Date在给定的容器中,然后 applies the custom strategy .

但是你的EncodableValue包装器,您没有给编码器执行此操作的机会,因为您是直接调用基础值的 encode(to:)方法。与 Date , 这个will encode the value using its default representation , 这是它的 timeIntervalSinceReferenceDate .

要解决此问题,您需要在单个值容器中对基础值进行编码,以触发任何自定义编码策略。这样做的唯一障碍是 protocols don't conform to themselves , 所以你不能调用容器的 encode(_:)使用 Encodable 的方法参数(因为参数采用 <Value : Encodable> )。

这个问题的一个解决方案是定义一个 Encodable用于编码到单值容器中的扩展,然后您可以在包装器中使用它:

extension Encodable {
fileprivate func encode(to container: inout SingleValueEncodingContainer) throws {
try container.encode(self)
}
}

struct AnyEncodable : Encodable {

var value: Encodable

init(_ value: Encodable) {
self.value = value
}

func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
try value.encode(to: &container)
}
}

这利用了协议(protocol)扩展成员具有隐式 <Self : P> 的事实。占位符在哪里 P是正在扩展的协议(protocol),隐含的 self参数被输入为这个占位符(长话短说;它允许我们调用 encode(_:) 符合 Encodable 的类型的方法)。

另一个选择是在你的包装器上有一个通用的初始化器,它通过存储一个进行编码的闭包来删除类型:

struct AnyEncodable : Encodable {

private let _encodeTo: (Encoder) throws -> Void

init<Value : Encodable>(_ value: Value) {
self._encodeTo = { encoder in
var container = encoder.singleValueContainer()
try container.encode(value)
}
}

func encode(to encoder: Encoder) throws {
try _encodeTo(encoder)
}
}

在这两种情况下,您现在都可以使用此包装器对异构可编码对象进行编码,同时遵守自定义编码策略:

import Foundation

struct Bar : Encodable, CustomStringConvertible {

let key: String
let value: AnyEncodable

var description: String {

let encoder = JSONEncoder()
let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "E, d MMM yyyy"
dateFormatter.locale = Locale(identifier: "en_US_POSIX")
encoder.dateEncodingStrategy = .formatted(dateFormatter)

guard let jsonData = try? encoder.encode(self) else {
return "Bar(key: \(key as Any), value: \(value as Any))"
}
return String(decoding: jsonData, as: UTF8.self)
}
}

print(Bar(key: "bar1", value: AnyEncodable("12345")))
// {"key":"bar1","value":"12345"}

print(Bar(key: "bar2", value: AnyEncodable(12345)))
// {"key":"bar2","value":12345}

print(Bar(key: "bar3", value: AnyEncodable(Date())))
// {"key":"bar3","value":"Wed, 7 Feb 2018"}

关于swift - JSONEncoder 的 dateEncodingStrategy 不工作,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48658574/

25 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com