Ответ 1
Да, но вам придется написать свой собственный кодер; вы не можете использовать значение по умолчанию.
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)
}
}
Кодирование необязательного напрямую будет кодировать нуль, как вы ищите.
Если это важный прецедент для вас, вы можете рассмотреть возможность открытия дефекта bugs.swift.org, чтобы запросить новый OptionalEncodingStrategy
флаг, который будет добавлен в JSONEncoder, чтобы соответствовать существующим DateEncodingStrategy
и т.д. (см. ниже, почему это, вероятно, невозможно реализовать в Swift сегодня, но попасть в систему отслеживания по-прежнему полезно по мере развития Swift.)
Изменить: к вопросам Пауло ниже, это отправляется в общую версию encode<T: Encodable>
, потому что Optional
соответствует Encodable
. Это реализовано в Codable.swift следующим образом:
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 обрабатывать опции как просто еще один кодирующий лучше, чем рассматривать их как особый случай в нашем собственном кодере и вызывать encodeNil
сами.
Еще один очевидный вопрос - почему он работает таким образом, в первую очередь. Поскольку параметр Необязательный кодируется, а сгенерированное кодируемое соответствие кодирует все свойства, почему "кодировать все свойства вручную" работают по-другому? Ответ заключается в том, что генератор соответствия включает специальный случай для опций:
// 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....)