If the dictionary uses String or Int keys, the contents are encoded in a keyed container. Otherwise, the contents are encoded as alternating key-value pairs in an unkeyed container.
extension Dictionary : Encodable where Key : Encodable, Value : Encodable {
/// Encodes the contents of this dictionary into the given encoder.
///
/// If the dictionary uses `String` or `Int` keys, the contents are encoded
/// in a keyed container. Otherwise, the contents are encoded as alternating
/// key-value pairs in an unkeyed container.
///
/// This function throws an error if any values are invalid for the given
/// encoder's format.
///
/// - Parameter encoder: The encoder to write data to.
@inlinable // FIXME(sil-serialize-all)
public func encode(to encoder: Encoder) throws {
if Key.self == String.self {
// Since the keys are already Strings, we can use them as keys directly.
var container = encoder.container(keyedBy: _DictionaryCodingKey.self)
for (key, value) in self {
let codingKey = _DictionaryCodingKey(stringValue: key as! String)!
try container.encode(value, forKey: codingKey)
}
} else if Key.self == Int.self {
// Since the keys are already Ints, we can use them as keys directly.
var container = encoder.container(keyedBy: _DictionaryCodingKey.self)
for (key, value) in self {
let codingKey = _DictionaryCodingKey(intValue: key as! Int)!
try container.encode(value, forKey: codingKey)
}
} else {
// Keys are Encodable but not Strings or Ints, so we cannot arbitrarily
// convert to keys. We can encode as an array of alternating key-value
// pairs, though.
var container = encoder.unkeyedContainer()
for (key, value) in self {
try container.encode(key)
try container.encode(value)
}
}
}
}
If you use enum case as key in Dictionary, JSONEncoder will encode it as Array. For example
The reason is how JSONEncoder checks for type https://github.com/apple/swift/blob/d2085d8b0e/stdlib/public/core/Codable.swift.gyb#L1967
Read more