How can I properly map RealmDB Results objects to SwiftUI Lists?

1.1k Views Asked by At

I am trying to display results of a realmdb query in a SwiftUI list but have trouble when deleting database objects.

I am trying to use something like this:

final class DBData: ObservableObject{

let didChange = PassthroughSubject<DBData, Never>()

private var notificationTokens: [NotificationToken] = []
var events = try! Realm().objects(ADMEvent.self)
@Published var events: [ADMEvent] = []
init() {
    // Observe changes in the underlying model
    self.notificationTokens.append(posts.observe { _ in
        self.events = Array(self.posts)
        self.didChange.send(self)
    })
}
}

Which works if I display items In a list but the moment I use realm.deleteAll() the app crashes because it looks like Swift UI's list implementation is trying to diff the list, accessing the now invalidated realm db objects.

There are like 3 or 4 similar questions on stack overflow but they are all out of date in one way or another, or work but still have this issue when it comes to deletion.

Thanks!

2

There are 2 best solutions below

2
On BEST ANSWER

Realm objects are live an autoupdating this is why they crash when you try to hold onto a deleted object. Instead of giving your publish subject the Realm.Object map it to a struct that has only the fields you need to use and use that array to drive SwiftUI.

struct Event: Identifiable {
  var id: String
  var name: String
  var date: Date
}

final class DBData: ObservableObject {
private var notificationTokens: [NotificationToken] = []
var events = try! Realm().objects(ADMEvent.self)
@Published var publishedEvents: [ADMEvent] = []
init() {
    // Observe changes in the underlying model
    self.notificationTokens.append(posts.observe { _ in
        self.publishedEvents = events.map { Event(id: $0.id, name: $0.name, date: $0.date)}
    })
}
}
0
On

I love this approach! I just want to put this out there because the accepted answer won't compile and has more than one issue:

@Published var publishedEvents: [ADMEvent] = []

should be:

@Published var publishedEvents: [Event] = []

and

 self.notificationTokens.append(posts.observe { _ in

should be:

 self.notificationTokens.append(events.observe { _ in

so

final class DBData: ObservableObject {
    private var notificationTokens: [NotificationToken] = []
    var events = try! Realm().objects(ADMEvent.self)
    @Published var publishedEvents: [Event] = []

    init() {
      // Observe changes in the underlying model
      self.notificationTokens.append(events.observe { _ in
        self.publishedEvents = events.map { Event(id: $0.id, name: $0.name, date: $0.date)}
      })
    }
}