是的,但是您必须编写您自己的encode(to:)
实现,您不能使用自动生成的实现.
struct Foo: Codable {
var string: String? = nil
var number: Int = 1
func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(number, forKey: .number)
try container.encode(string, forKey: .string)
}
}
直接编码可选的将编码一个NULL,就像您正在寻找的那样.
如果这是一个对您来说很重要的用例,您可以考虑在bugs.swift.org处打开一个缺陷,要求在JSONEncoding上添加一个新的OptionalEncodingStrategy
标志,以匹配现有的DateEncodingStrategy
,以此类推.(请参阅下面的原因,为什么这可能无法在今天的SWIFT中实际实施,但随着SWIFT的发展,进入跟踪系统仍然很有用.)
编辑:对于保罗下面的问题,这将发送到通用encode<T: Encodable>
版本,因为Optional
符合Encodable
.这是通过以下方式实现的:
extension Optional : Encodable /* where Wrapped : Encodable */ {
@_inlineable // FIXME(sil-serialize-all)
public func encode(to encoder: Encoder) throws {
assertTypeIsEncodable(Wrapped.self, in: type(of: self))
var container = encoder.singleValueContainer()
switch self {
case .none: try container.encodeNil()
case .some(let wrapped): try (wrapped as! Encodable).__encode(to: &container)
}
}
}
这将调用包装为encodeNil
,我认为让stdlib将可选参数作为另一个Encodable处理要比在我们自己的编码器中将它们作为特例处理并自己调用encodeNil
要好.
另一个显而易见的问题是,它为什么会以这种方式工作.既然Optional是可编码的,并且生成的可编码一致性对所有属性进行编码,为什么"手工编码所有属性"的工作方式不同?答案是一致性生成器includes a special case for Optionals:
// Now need to generate `try container.encode(x, forKey: .x)` for all
// existing properties. Optional properties get `encodeIfPresent`.
...
if (varType->getAnyNominal() == C.getOptionalDecl() ||
varType->getAnyNominal() == C.getImplicitlyUnwrappedOptionalDecl()) {
methodName = C.Id_encodeIfPresent;
}
这意味着更改此行为需要更改自动生成的一致性,而不是JSONEncoder
(这也意味着在今天的SWIFT中可能真的很难使其可配置……)