I've been doing my checklist app with local Realm database and stuck with code where I need to change category of item in the list.
There are several checklists and I would like to move my Objects (checklist items) between checklists. To give you an idea of my data structure: trip.checklist[indexPath.section].sectionChecklist[indexPath.row]
I've tried a method to delete Object and immediately add it to other list, but it expectedly comes to the error:
"Adding a deleted or invalidated object to a Realm is not permitted"
The code was:
func updateChecklistCategory(checklistSection: ChecklistSection, checklistItem: ChecklistElement) {
let realm = getRealm()
deleteObject(object: checklistItem)
addItemToCategory(checklistSection: checklistSection, checklistItem: checklistItem)
}
func addItemToCategory(checklistSection: ChecklistSection, checklistItem: ChecklistElement) {
let realm = getRealm()
do {
try realm.write {
checklistSection.sectionChecklist.append(checklistItem)
}
}
catch {
print("Error updating objects")
}
}
Is there any elegant way to do such movements? I understand it's possible if I initialize completely new Object with the same data, but it seems wrong.
CodePudding user response:
This is a great question.
Lists do not contain objects, only references to objects. So you can add and remove objects freely from Lists without affecting the actual object.
If you want to 'move' an object from one list to another, here's an example of moving a dog object from one person's List to another.
If you know the index to the object within the List you can get a reference the dog object directly from the list. If not, query for that object, find it in the list, remove it from the List and then add the dog to the new List. Do NOT delete or do anything to the actual dog object.
class PersonClass: Object {
@Persisted var name = ""
@Persisted var dogList: List<Dog>()
}
class DogClass: Object {
@Persted var dogName = ""
}
then let's add a dog 'Spot' to Jay's dogList
let dog = DogClass()
dog.name = "Spot"
let jay = PersonClass()
jay.name = "Jay"
jay.dogList.append(dog) //Jay has a dog
let cindy = PersonClass()
cindy.name = "Cindy" //Cindy has no dog
try! realm.write {
realm.add([jay, cindy])
}
then later we want to move the dog Spot from Jay to Cindy
let spot = realm.objects(DogClass.self).first! //get the spot object
//or: if you know the index you can get a dog reference from the list
// let spot = jay.dogList[0] //a reference to the dog at index 0 in this case
let jay = realm.objects(PersonClass.self).where { $0.name == "Jay"}.first!
let cindy = realm.objects(PersonClass.self).where { $0.name == "Cindy"}.first!
try! realm.write {
//if you don't know the index of the dog, get it
if let dogIndex = jay.dogList.firstIndex(of: spot) { //get spots position in the dogList
jay.dogList.remove(at: dogIndex) //removed dog from jay's dogList - this does not alter the dog object
cindy.dogList.append(spot) //and then add the dog to cindy's dogList
}
//if you know the index of the dog, get a reference to it
// let spot = jay.dogList[0] //a reference to the dog at index 0 in this case
// jay.dogList.remove(at: 0) //removed dog from jay's dogList - this does not alter the dog object
// cindy.dogList.append(spot) //and then add the dog to cindy's dogList
}
The key is that Realm List collection objects only contains references to the actual object stored on disk - not the actual object - those references can be added or removed without affecting the object itself.
Keep in mind though, that if you want to modify the actual object within the List, you'll need to use the reference to get the actual object, and then modify it within a write transaction. That change will reflect in ALL other Lists that reference that object.
So in the above example, if Spot was in both Jay and Cindys List, and Spot's name was modified to be "Buttons", then it changes the name on disk and Jay and Cindy's dog would now be Buttons