A bit late to the party, but I think this is great opportunity for JSONEncoder
and JSONSerialization
.
The accepted answer does touch on this, this solution saves us calling JSONSerialization
every time we access a key, but same idea!
extension Encodable {
/// Encode into JSON and return `Data`
func jsonData() throws -> Data {
let encoder = JSONEncoder()
encoder.outputFormatting = .prettyPrinted
encoder.dateEncodingStrategy = .iso8601
return try encoder.encode(self)
}
}
You can then use JSONSerialization
to create a Dictionary
if the Encodable
should be represented as an object in JSON (e.g. Swift Array
would be a JSON array)
Here's an example:
struct Car: Encodable {
var name: String
var numberOfDoors: Int
var cost: Double
var isCompanyCar: Bool
var datePurchased: Date
var ownerName: String? // Optional
}
let car = Car(
name: "Mazda 2",
numberOfDoors: 5,
cost: 1234.56,
isCompanyCar: true,
datePurchased: Date(),
ownerName: nil
)
let jsonData = try car.jsonData()
// To get dictionary from `Data`
let json = try JSONSerialization.jsonObject(with: jsonData, options: [])
guard let dictionary = json as? [String : Any] else {
return
}
// Use dictionary
guard let jsonString = String(data: jsonData, encoding: .utf8) else {
return
}
// Print jsonString
print(jsonString)
Output:
{
"numberOfDoors" : 5,
"datePurchased" : "2020-03-04T16:04:13Z",
"name" : "Mazda 2",
"cost" : 1234.5599999999999,
"isCompanyCar" : true
}