When I receive JSON from an API call, when decoding it I have structs like this:
import Foundation
struct JSON: Codable {
var alpha: Alpha
var beta: Beta
var gamma: [Gamma]?
}
I want to save the JSON in my Realm database, to later use and traverse like JSON. It's my understanding that I can't just use the existing structs I have written, instead I have to rewrite a second (similar) class like this to use with Realm:
import Foundation
import RealmSwift
class RealmJSON: Object, Identifiable {
@Persisted (primaryKey: true) var id: ObjectId
@Persisted var alpha: RealmAlpha
@Persisted var beta: RealmBeta
@Persisted var gamma: RealmSwift.List<RealmGamma>?
override class func primaryKey() -> String? {
"id"
}
convenience init(id: ObjectId, alpha: RealmAlpha, beta: RealmBeta, gamma: RealmSwift.List<RealmGamma>?) {
self.init()
self.id = id
self.alpha = alpha
self.beta = beta
self.gamma = gamma
}
}
Obviously, this is inconvenient especially when dealing with large amounts of JSON. Moreover I want to use Swagger codegen to write the client code for me, but it kind of defeats the purpose if I then have to manually add the Realm classes manually.
Is this the only way for dealing with JSON and a Realm database, or am I missing something here?
EDIT: I realise a simple way is to store most of the JSON as a raw JSON string with properties to identify schema type / version. Then I can just fetch the correct schema I require and parse the rawJSON string with the existing JSON structs...
You can pass the json data directly to your objects. I can think of two ways.
The first way, conform to Codable
.
class Dog: Object, Codable {
@Persisted var name: String
}
class Cat: Object, Codable {
@Persisted var name: String
}
class Kid: Object, Codable {
@Persisted var name: String
}
class Owner: Object, Codable {
@Persisted var name: String
@Persisted var dog: Dog?
@Persisted var cat: Cat?
@Persisted var kids: List<Kid>
}
Let's use the following method to make json data:
func makeData() -> Data {
let string = """
{
"name": "Tom",
"kids": [{"name": "Penelope"}, {"name": "Rob"}],
"cat": {"name": "Lilly"},
"dog": {"name": "Lucy"}
}
"""
return string.data(using: .utf8)!
}
Now we can create our objects:
func decodeOwner() {
let decoder = JSONDecoder()
let owner = try! decoder.decode(Owner.self, from: makeData())
print("Decoded:", owner)
}
Another way is to use JSONSerialization and use the result to pass to the value constructor:
extension Object {
convenience init(json: Data) throws {
let data = try JSONSerialization.jsonObject(with: json)
self.init(value: data)
}
}
func serializeOwner() {
let owner = try! Owner(json: makeData())
print("Serialization:", owner)
}