Successfully write JSON to Realm DB using swiftyJSON in Swift

724 views Asked by At

I am trying to write to a Realm DB from JSON file (using swiftyJSON) get the following error:

libc++abi.dylib: terminating with uncaught exception of type NSException *** Terminating app due to uncaught exception 'RLMException', reason: 'Invalid value '{ "vehicle" : true, "viewable" : true, "id" : 0, "weapon" : false, "genres" : "[Fantasy, General]", "name" : "Car" }' to initialize object of type 'Item': missing key 'id''

My JSON file is structured as follows:

  [
  {
    "id": 0,
    "name": "Car",
    "genres": "[Fantasy, General]",
    "viewable": true,
    "weapon": false,
    "vehicle": true
  },
  {
    "id": 1,
    "name": "Truck",
    "genres": "[General]",
    "viewable": true,
    "weapon": false,
    "vehicle": true
  },
]

My Realm DB Class is:

class Item: Object {
    @objc dynamic var id: Int = 0
    @objc dynamic var name = ""
    let genres = List<String>()
    @objc dynamic var visable: Bool = false
    @objc dynamic var weapon: Bool = false
    @objc dynamic var vehicle: Bool = false
    
    override static func primaryKey() -> String? {
        return "id"
    }
    
    override static func indexedProperties() -> [String] {
        return ["genre", "visable"]
    }
    
}

and the code to write the JSON to the RealmDB is as follows:

func jsonAdd() {

    if let path = Bundle.main.path(forResource: "Data", ofType: "json") {
        do {
            let data = try Data(contentsOf: URL(fileURLWithPath: path), options: .mappedIfSafe)
            let json = JSON(data)
            
            for (index,subJson):(String, JSON) in json {
                
                do {
                    try realm.write {
                        
                        realm.create(Item.self, value: subJson, update: .modified)
                        
                    }
                    
                } catch let error as NSError {
                    print("Unable to write")
                    print(error)
                }
                
            }
            
        } catch {
            print("Error")
        }
        
    }
}

I think the issue is a JSON mapping one but any help will be greatly appreciated to write the JSON to the Realm DB including the genres as a List.

NB: I've managed to write to the Realm DB using the following code (based off the Realm documentation) before the 'Write' function but cannot seem to get it to work for my JSON structure.

 let newdata = "{\"id\": 0, \"name\": \"Car\", \"genres\": [\"Fantasy\",\"General\"], \"viewable\": true, \"weapon\": false, \"vehicle\": true}".data(using: .utf8)!
    
 let json = try! JSONSerialization.jsonObject(with: newdata, options: [])

Thank you!

1

There are 1 answers

0
ecjps82 On BEST ANSWER

Solved through the following approach:

  1. Slight change to my JSON structure as follows:

     [
       {
         "id": 0,
         "name": "Car",
         "genres": ["Fantasy", "General"],
         "viewable": true,
         "weapon": false,
         "vehicle": true
       },
       {
         "id": 1,
         "name": "Truck",
         "genres": ["Fantasy", "General"],
         "viewable": true,
         "weapon": false,
         "vehicle": true
       }
     ]
    
  2. Created a new Genres Object to better handle the list

     class Genres: Object {
         @objc dynamic var id = 0
         @objc dynamic var name = ""
    
         override static func primaryKey() -> String? {
             return "id"
         }
     }
    
     class Item: Object {
         @objc dynamic var id = 0
         @objc dynamic var name = ""
         var genres = List<Genres>()
         @objc dynamic var viewable: Bool = false
         @objc dynamic var weapon: Bool = false
         @objc dynamic var vehicle: Bool = false
    
         override static func primaryKey() -> String? {
             return "id"
         }
    
         override static func indexedProperties() -> [String] {
             return ["genres", "viewable"]
         }
    
     }
    

3)Crucially in the jsonADD function updated the code to create a new Item Object then mapped the JSON values to that object before attempting to write to the Realm DB:

for (key,subJson):(String, JSON) in jsonObjects {
        
        let thisItem = Item()
        thisItem.id = subJson["id"].intValue
        thisItem.name = subJson["name"].stringValue
        thisItem.visable = subJson["viewable"].boolValue
        thisItem.weapon = subJson["weapon"].boolValue
        thisItem.vehicle = subJson["vehicle"].boolValue
        
        let genreArray = subJson["genres"].arrayValue
        
        for genre in genreArray {
            let string = genre.stringValue
            let predicate = NSPredicate(format: "name = %@", string)
            
            if let foundGenre = realm.objects(Genres.self).filter(predicate).first {
                thisItem.genres.append(foundGenre)
            }
        }
        
        do {
            try realm.write {
                realm.create(Item.self, value: thisItem, update: .modified)
            }
            
        } catch let error as NSError {
            print("Unable to write")
            print(error)
        }
    }