How should I model a dictionary property on a Realm object so when encoded to JSON I can get this:
{
"firstName": "John",
"lastName": "Doe",
"favoriteThings": {
"car": "Audi R8",
"fruit": "strawberries",
"tree": "Oak"
}
}
I tried creating a new Object FavoriteThings with 'key' and 'value' properties as I've seen elsewhere...
public class Person: Object {
@objc dynamic var firstName = ""
@objc dynamic var lastName = ""
var favoriteThings = List<FavoriteThings>()
}
But List gives me an array, naturally, when I encode it to JSON. I don't want an array. I'm using Swift Codable.
{
"firstName": "John",
"lastName": "Doe",
"favoriteThings": [
{
"key": "fruit",
"value": "strawberries"
},
{
"key": "tree",
"value": "Oak"
}
],
}
Any pointers appreciated!
Gonzalo
As you know, Lists are encoded into json arrays by default. So, to encode a List into a Dictionary you'll have to implement a custom encode method to do exactly that.
public class FavoriteThings: Object {
@objc dynamic var key = ""
@objc dynamic var value = ""
convenience init(key: String, value: String) {
self.init()
self.key = key
self.value = value
}
}
public class Person: Object, Encodable {
enum CodingKeys: String, CodingKey {
case firstName
case lastName
case favoriteThings
}
@objc dynamic var firstName = ""
@objc dynamic var lastName = ""
let favoriteThings = List<FavoriteThings>()
convenience init(firstName: String, lastName: String, favoriteThings: [FavoriteThings]) {
self.init()
self.firstName = firstName
self.lastName = lastName
self.favoriteThings.append(objectsIn: favoriteThings)
}
public func encode(to encoder: Encoder) throws {
var container = encoder.container(keyedBy: CodingKeys.self)
try container.encode(firstName, forKey: .firstName)
try container.encode(lastName, forKey: .lastName)
var favThings: [String: String] = [:]
for thing in favoriteThings {
favThings[thing.key] = thing.value
}
try container.encode(favThings, forKey: .favoriteThings)
}
}
And the usage would be like this:
func testEncode() {
let john = Person(
firstName: "John",
lastName: "Doe",
favoriteThings: [
.init(key: "car", value: "Audi R8"),
.init(key: "fruit", value: "strawberries"),
.init(key: "tree", value: "Oak"),
])
let encoder = JSONEncoder()
let data = try! encoder.encode(john)
if let string = String(data: data, encoding: .utf8) {
print(string)
}
}
Which prints:
{"firstName":"John","favoriteThings":{"car":"Audi R8","fruit":"strawberries","tree":"Oak"},"lastName":"Doe"}