In most cases, I'd probably use SeaSpell or Sh_Khan's solutions. Bool? is usually not the right type, but in this case it seems precisely what you mean (you seem to want to keep track of whether the value was set or not, rather than defaulting to something). But those approaches do require a custom decoder for the whole type which might be inconvenient. Another approach would be to define a new type just for this 3-way value:
enum Maintenance {
case `true`, `false`, unset
}
(Maybe "enabled" and "disabled" would be better here than taking over the true and false keywords. But just showing what Swift allows.)
You can then decode this in a very strict way, checking for true, false, or "" and rejecting anything else ("false" for example).
extension Maintenance: Decodable {
init(from decoder: Decoder) throws {
let container = try decoder.singleValueContainer()
if let value = try? container.decode(Bool.self) {
self = value ? .true : .false
} else if let value = try? container.decode(String.self), value.isEmpty {
self = .unset
} else {
throw DecodingError.dataCorruptedError(in: container,
debugDescription: "Unable to decode maintenance")
}
}
}
Depending on how the rest of your code work, this three-way enum may be more convenient or less convenient than an Optional Bool, but it's another option.
With this, you don't need anything special in Demo:
struct Demo: Decodable {
var maintenance: Maintenance
}
An important distinction is that maintenance here is not optional. It is required. There are just three acceptable values. Even if using Bool? you should think hard about whether there is a difference between "" and missing.