I have been able to save data in a Realm database, but have been unable to show the results in a SwiftUI List
.
I know I have the data and have no problem printing the results in the console.
Is there a way to convert Realm Result
into a format that can be displayed on a SwiftUI List
?
import SwiftUI
import RealmSwift
import Combine
class Dog: Object {
@objc dynamic var name = ""
@objc dynamic var age = 0
override static func primaryKey() -> String? {
return "name"
}
}
class SaveDog {
func saveDog(name: String, age: String) {
let dog = Dog()
dog.age = Int(age)!
dog.name = name
// Get the default Realm
let realm = try! Realm()
print(Realm.Configuration.defaultConfiguration.fileURL!)
// Persist your data easily
try! realm.write {
realm.add(dog)
}
print(dog)
}
}
class RealmResults: BindableObject {
let didChange = PassthroughSubject<Void, Never>()
func getRealmResults() -> String{
let realm = try! Realm()
var results = realm.objects(Dog.self) { didSet
{didChange.send(())}}
print(results)
return results.first!.name
}
}
struct dogRow: View {
var dog = Dog()
var body: some View {
HStack {
Text(dog.name)
Text("\(dog.age)")
}
}
}
struct ContentView : View {
@State var dogName: String = ""
@State var dogAge: String = ""
let saveDog = SaveDog()
@ObjectBinding var savedResults = RealmResults()
let realm = try! Realm()
let dogs = Dog()
var body: some View {
VStack {
Text("Hello World")
TextField($dogName)
TextField($dogAge)
Button(action: {
self.saveDog.saveDog(name: self.dogName,
age:self.dogAge)
// self.savedResults.getRealmResults()
}) {
Text("Save")
}
//insert list here to show realm data
List(0 ..< 5) {
item in
Text(self.savedResults.getRealmResults())
} //Displays the same thing 5 times
}
}
}
#if DEBUG
struct ContentView_Previews : PreviewProvider {
static var previews: some View {
ContentView()
}
}
#endif
Some of the code probably may not make sense because I was attempting several approaches to see if anything would work.
This line, for example, will display the result in the List View.
return results.first!.name
If I just return results, nothing displays in the List Text View.
As I have commented below I will attempt the ForEach approach when I have time. That looks promising.
Realm objects have bindings to SwiftUI controls and, much like toggling the bought property, they already start a realm transaction to write the changes in the database whenever you change those values.
If your project requires encryption or speed, then Realm is an obvious choice. If your project has a complex data model that changes frequently, then Core Data might be a better choice.
The Realm Database Swift SDK enables mobile applications to access data stored in local realms. Optionally, interact with Atlas App Services features such as Functions, MongoDB Data Access, and authentication. The Realm Swift SDK supports Swift and Objective-C, and provides SwiftUI-friendly property wrappers.
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)
}
}
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With