I am using Codable with Realm on iOS and is finding issue with updating existing records saved in Realm. Data consists of a list of Items where each of the items has List of categories and each category has a description.
This is how my Realm Codable models look like
class Items: Object, Decodable {
@objc dynamic var id: String = ""
@objc dynamic var name: String = ""
let categories = List<Categories>()
@objc dynamic var desc: Desc?
override static func primaryKey() -> String? {
return "id"
}
var hasSubCategories: Bool {
if self.categories.count > 0 {
return true
}
return false
}
enum CodingKeys: String, CodingKey {
case id
case name
case desc
case categories
}
required init() {
super.init()
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
name = try container.decode(String.self, forKey: .name)
desc = try (container.decodeIfPresent(Desc, forKey: .desc))
let categoriesList = try container.decodeIfPresent(List<Categories>.self, forKey: .categories) ?? List<Categories>()
categories.append(objectsIn: categoriesList)
super.init()
}
}
class Categories: Object, Decodable {
@objc dynamic var id: String = ""
@objc dynamic var name: String = ""
@objc dynamic var desc: Desc?
let categories = List<Categories>()
override static func primaryKey() -> String? {
return "id"
}
var hasSubCategories: Bool {
if categories.count > 0 {
return true
}
return false
}
enum CodingKeys: String, CodingKey {
case id
case name
case categories
}
required init() {
super.init()
}
required init(from decoder: Decoder) throws {
let container = try decoder.container(keyedBy: CodingKeys.self)
id = try container.decode(String.self, forKey: .id)
name = try container.decode(String.self, forKey: .name)
desc = try (container.decodeIfPresent(Desc, forKey: . desc))
let categoriesList = try container.decodeIfPresent(List<Categories>.self, forKey: .categories) ?? List<Categories>()
categories.append(objectsIn: categoriesList)
super.init()
}
}
I add new Items received from API with following code
let realm = try? Realm()
for item in ItemsFromAPI {
do {
try realm?.write {
realm?.add(item)
}
}
}
When a data already saved in DB is received from API, I need to update it. As per my understanding, with primarykey implemented
realm?.add(Item, update: .modified)
will update the existing record which has the same primary. Properties of object with class Item are updated but the List<> of categories are not getting updated.
I tried to fetch existing list of categories saved in database and mutated the categories object associated with savedItem by calling savedItem.categories.removeAll() and added new categories with savedItem.categories.append(objectsIn: itemFromAPI.categories)
When i save this with
realm?.add(Item, update: .modified)
Realm crashing throwing an exception - “RLMException reason: Attempting to create an object of type with an existing primary key value”
So I tried removing the category with
realm?.delete(Category)
and then added the modified Category associated with Item and this is working.
I have nested Categories to multiple levels and updating them by fetching it again, deleting them and readding them again is proving to be a pain. Is this how update records work in realm?
Can I update the nested category related to an item by simply assigning the new object against an item and use the
realm?.add(Item, update: .modified)
to update the records like its done for adding a new item?
Any response would be greatly appreciated.