Успешно записать JSON в Realm DB с помощью swiftyJSON в Swift

Я пытаюсь записать в Realm DB из файла JSON (используя swiftyJSON), получаю следующую ошибку:

libc ++ abi.dylib: завершение с неперехваченным исключением типа NSException *** Завершение работы приложения из-за неперехваченного исключения 'RLMException', причина: 'Недопустимое значение' {vehicle: true, viewable: true, id: 0, weapon: false, жанры: [Fantasy, General], name: Car} 'для инициализации объекта типа' Item ': отсутствует ключ' id ''

Мой файл JSON имеет следующую структуру:

  [
  {
    "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
  },
]

Мой класс БД Realm:

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"]
    }
    
}

а код для записи JSON в RealmDB выглядит следующим образом:

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")
        }
        
    }
}

Я думаю, что проблема связана с отображением JSON, но мы будем очень благодарны за любую помощь, чтобы записать JSON в базу данных Realm, включая жанры в виде списка.

NB: Мне удалось записать в базу данных Realm, используя следующий код (на основе документации Realm) перед функцией «Запись», но, похоже, не могу заставить ее работать для моей структуры JSON.

 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: [])

Спасибо!


person ecjps82    schedule 06.02.2021    source источник
comment
Немного не по теме, но Realm не поддерживает Список примитивных объектов (очень хорошо). Итак, вы захотите изменить это let genres = List<String>() на let genres = List<MyStringClass>(). Дополнительные сведения см. здесь. Также существует проблема с первичным ключом объекта, которым является Int, и описывающая его функция override static func primaryKey() -> String?, возвращающая String   -  person Jay    schedule 07.02.2021
comment
Спасибо за ваш комментарий @Jay - я принял ваше предложение и создал class Genres: Object и заменил жанры на let genres = List<Genres>(). Мне также удалось решить свою проблему, поэтому вскоре я опубликую ответ.   -  person ecjps82    schedule 08.02.2021


Ответы (1)


Решается с помощью следующего подхода:

  1. Небольшие изменения в моей структуре JSON следующим образом:

     [
       {
         "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. Создан новый объект "Жанры", чтобы лучше обрабатывать список.

     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) В функции jsonADD принципиально обновлен код для создания нового объекта Item, а затем сопоставлены значения JSON с этим объектом перед попыткой записи в базу данных Realm:

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)
        }
    }
person ecjps82    schedule 08.02.2021