Why do I get an error when deleting data from SwiftUI List and Realm?

Hi all,


I know this is may not be the right forum to post questions about Realm but my issue has to do with the nature of how SwiftUI works.


Has anyone been able to successfully integrate

Realm
with
SwiftUI
, especially deleting records/rows from a
SwiftUI List
? I have tried a few different things but no matter what I do I get the same error. After reading some related threads I found out that other people have the same issue but I refuse to think that there is no current solution to integrate Realm with SwiftUI.


The following code successfully presents all of the items from

Realm
in a
SwiftUI List
, I can create new ones and they show up in the
List
as expected, my issues is when I try to delete records from the
List
by either manually pressing a button or by left-swiping to delete the selected row, I get an Index is out of bounds error.


Here is my code.


Realm Model:


class Dog: Object {
    @objc dynamic var name = ""
    @objc dynamic var age = 0
    @objc dynamic var createdAt = NSDate()
   
    @objc dynamic var userID = UUID().uuidString
    override static func primaryKey() -> String? {
        return "userID"
    }
}


SwiftUI Code:


class BindableResults: ObservableObject where Element: RealmSwift.RealmCollectionValue {
    var results: Results
    
    private var token: NotificationToken!
    
    init(results: Results) {
        self.results = results
        lateInit()
    }
    func lateInit() {
        token = results.observe { [weak self] _ in
            self?.objectWillChange.send()
        }
    }
    deinit {
        token.invalidate()
    }
}


struct DogRow: View {
    var dog = Dog()
    var body: some View {
        HStack {
            Text(dog.name)
            Text("\(dog.age)")
        }
    }
}




struct ContentView : View {


    @ObservedObject var dogs = BindableResults(results: try! Realm().objects(Dog.self))


    var body: some View {
        VStack{
                
        List{
            ForEach(dogs.results, id: \.name) { dog in
                DogRow(dog: dog)
            }.onDelete(perform: deleteRow )
        }
           
            Button(action: {
                try! realm.write {
                    realm.delete(self.dogs.results[0])
                }
            }){
                Text("Delete User")
            }
        }
    }
    
    private func deleteRow(with indexSet: IndexSet){
        indexSet.forEach ({ index in
            try! realm.write {
                realm.delete(self.dogs.results[index])
            }
        })
    }
}

ERROR

Terminating app due to uncaught exception ‘RLMException’, reason: ‘Index 23 is out of bounds (must be less than 23).’

Of course, the

23
changes depending on how many items are in the
Realm
database, in this case, I had 24 records when I swiped and tapped the delete button.

Which line do you get the error ?

- line 46, executed line 62 ?

On this line, I don't understand what is done (I do not know Realm syntax): why write something you delete ?

- line 51 ?

Why delete results[0]

Once done, there is an index less, maybe that causes error line 46


More globally, looks like you delete twice a row: line 46 (done in 62) and line 51

Yes, line 46 executes the deleteRow() method. try! realm.write is the Realm syntax to be able to perform changes to the database. I'm deleting results[0] when a button is tapped just to test and make sure it wasn't the swipe delete causing the error. Deleting results[0] should indeed remove the first item and refresh the List but it's not doing it, that's mainly my issue. It does work when adding new items to Realm.


For instance, if I add a new dog object the List immediately updates.


                try! realm.write{
                    realm.add(dog)
                }


The error points to the appDelegate.swift file (Thread 1: signal SIGABRT).


Thanks!

You can't use Realm Collections with SwiftUI (or other reactive languages). The basic issue is because when you delete the realm object the object is marked as invalid and any attempt to access it's properties throws an exception - pretty brutal huh !! No quiet - sorry this is not allowed !

The way SwiftUI works is is keeps track of the list of items and when the list changes it gets notified that something changes and then it diffs the new list with the old list and neatly adds or removes items as required. Herein lies the problem - it still has a reference to the now deleted object in realm and attempts to access its properties causing an exception - OR - in your case it is checking the OLD list, which is actually a live updating REALM collection, which already has the item removed - and hence the index out of bounds error.

Check out the new frozen() option and the same in the 5.2.0 SwiftRealm release - not sure if that completely fixes the issue, but lets hope so !

Not a great solution but my work around was copying each realm result to a local object/array.

 class ContentViewController: ObservableObject {
    private var realmLocalData: [ScheduleModel] = [ScheduleModel]()
    private let realm = try! Realm()
    
    func updateData() {
      realmLocalData.removeAll()
      let predicate = NSPredicate(format: "dateIndex >= %@ && dateIndex <= %@", argumentArray: [startDate, endDate])
      let data = self.realm.objects(MonthScheduleModel.self).filter(predicate)
     
      for obj in data {
        realmLocalData.append(ScheduleModel(realmObj: obj))
      }
    }
Why do I get an error when deleting data from SwiftUI List and Realm?
 
 
Q