user-44651
user-44651

Reputation: 4124

Merge a Realm and Codable class in Swift 4

I am trying to kill two birds with one class.

I want to consume some JSON data and save it to a Realm database.

Here is my JSON data

{ "Colors": 
    [   {"Name" : "Blue"},
        {"Name" : "Red"},
        {"Name" : "Green"},
        {"Name" : "Black"}
    ]
}

I already have a Realm class that works fine.

class Color : Object {
    //RealmObject
    @objc dynamic var name  : String = ""
}

And when I use it

import SwiftyJSON
import RealmSwift

func process(jsonData: JSON) {
    for color in jsonData.arrayValue {
        let c = Color()
        c.name = color["Name"]
        save(data: c)
    }
}

func save(data: Object){
        do{
            try realm.write {
                realm.add(data)
            }

        } catch {
            print("Error saving data: \(error)")
        }
}

Then I updated my I updated my Color class to conform to Codable

class Color : Object, Codable {
    //RealmObject
    @objc dynamic var name  : String = ""

    //Codable For JSON Deserialziation
    enum CodingKeys: String, CodingKey {
        case name = "Name"
    }

}

struct Colors: Codable {
    let colors: [Color]

    enum CodingKeys: String, CodingKey {
        case colors = "Colors"
    }
}

What I would like to do something to the effect of Coding the jsonData and saving it to Realm.

if let colors = try? JSONDecoder().decode(Colors.self, from: data.rawData()) {
   self.save(data: colors)
}

But I cant seem to get it working. I have tried multiple ways I get the error:

Cannot convert value of type 'Colors?' to expected argument type 'Object'

Or trying to for the colors

Type 'Colors' does not conform to protocol 'Sequence'

Is this possible to do?

Upvotes: 0

Views: 1346

Answers (2)

David Pasztor
David Pasztor

Reputation: 54716

The issue is that colors is of type Colors, which is not an Object subclass, but it has a property of type [Color]. You either need to iterate through the property and save each object individually or even better, overload save to handle an array of Object subclass instances.

func save<T:Object>(objects: [T]){
    do{
        try realm.write {
            realm.add(objects)
        }
    } catch {
        print("Error saving data: \(error)")
    }
}

Then save the objects:

if let colors = try? JSONDecoder().decode(Colors.self, from: data.rawData()) {
   self.save(objects: colors.colors)
}

Upvotes: 1

Shehata Gamal
Shehata Gamal

Reputation: 100523

Replace this

self.save(data: colors)

with

colors.colors.forEach { self.save(data:$0) }

as colors here

if let colors = try? JSONDecoder().decode(Colors.self, from: data.rawData()) {---}

is an object that contains an array property colors of type Color

Upvotes: 1

Related Questions