Issue #860
JSONEncoder
deals with type-safe, so we need to declare an enum JSONValue
for all possible types. We also need a custom initializer to init JSONValue
from a JSON Dictionary
import Foundation
enum JSONValue {
case string(String)
case int(Int)
case double(Double)
case bool(Bool)
case object([String: JSONValue])
case array([JSONValue])
}
extension JSONValue: Encodable {
public func encode(to encoder: Encoder) throws {
var container = encoder.singleValueContainer()
switch self {
case .string(let string): try container.encode(string)
case .int(let int): try container.encode(int)
case .double(let double): try container.encode(double)
case .bool(let bool): try container.encode(bool)
case .object(let object): try container.encode(object)
case .array(let array): try container.encode(array)
}
}
}
extension JSONValue {
init?(any: Any) {
if let value = any as? String {
self = .string(value)
} else if let value = any as? Int {
self = .int(value)
} else if let value = any as? Double {
self = .double(value)
} else if let value = any as? Bool {
self = .bool(value)
} else if let json = any as? [String: Any] {
var dict: [String: JSONValue] = [:]
for (key, value) in json {
dict[key] = JSONValue(any: value)
}
self = .object(dict)
} else if let jsonArray = any as? [Any] {
let array = jsonArray.compactMap { JSONValue(any: $0) }
self = .array(array)
} else {
return nil
}
}
}
var dict: [String: Any] = [
"anArray": [1, 2, 3],
"anObject": [
"key1": "value1",
"key2": "value2"
],
"aString": "hello world",
"aDouble": 1.2,
"aBool": true,
"anInt": 12
]
let encoder = JSONEncoder()
let value = JSONValue(any: dict)
let data = try! encoder.encode(value)
print(String(data: data, encoding: .utf8))