How to Display Realm Results in Swiftui List

How to display Realm Results in SwiftUI List?

The data that you pass in List or a ForEach must conform to the Identifiable protocol.

Either you adopt it in your Realm models or you use .identified(by:) method.


Even with that, the View won't reload if the data changes.

You could wrap Results and make it a BindableObject, so the view can detect the changes and reload itself:

class BindableResults<Element>: ObservableObject where Element: RealmSwift.RealmCollectionValue {

var results: Results<Element>
private var token: NotificationToken!

init(results: Results<Element>) {
self.results = results
lateInit()
}

func lateInit() {
token = results.observe { [weak self] _ in
self?.objectWillChange.send()
}
}

deinit {
token.invalidate()
}
}

And use it like:

struct ContentView : View {

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

var body: some View {
List(dogs.results.identified(by: \.name)) { dog in
DogRow(dog: dog)
}
}

}

What is the right way to present data from Realm in SwiftUI List

Probably you meant this

ForEach(allUsers, id:\.self) { user in
Text(user.name)
}

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

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

How to use Realm with SwiftUI

Sure, it's very simple, use the module identifier as prefix like this :

let members = RealmSwift.List<Member>()

Now to the second part of your question. It's easy to encapsulate a Realm object (or list, or resultset) in an BindableObject :

final class DBData: BindableObject  {

let didChange = PassthroughSubject<DBData, Never>()

private var notificationTokens: [NotificationToken] = []
var posts = Post.all

init() {
// Observe changes in the underlying model
self.notificationTokens.append(posts.observe { _ in
self.didChange.send(self)
})

self.notificationTokens.append(Message.all.observe { _ in
self.didChange.send(self)
})
}
}

If you "link" a DBData instance to a SwiftUI View by either using @ObjectBinding or @EnvironmentObject the UI will be refreshed and the new value for posts (in our example here) will be available each time the underlying realm changes.

Realm with SwiftUI Returning List ShoppingItem

It conflicts with SwiftUI.List, so you need to add module explicitly

var items: RealmSwift.List<ShoppingItem>

SwiftUI App Shows Realm Changes but Not New Objects

Realm Results objects are live-updating objects and always reflect the current state of those objects in Realm.

However, if you cast your Realm Results object to an array

items = Array(results)

It 'disconnects' those objects ( the results ) from Realm and it (they) are no longer live updating.

Additionally Realm Results objects are lazily-loaded, meaning that they are only loaded into memory when needed so thousands of objects take up almost no space.

Storing them in an array changes that - they are all loaded into memory and could overwhelm the device.

Best practice is to leave Realm Collections (Results, Lists) as that type of object throughout the duration of using them instead of casting to an array.



Related Topics



Leave a reply



Submit