Как отобразить результаты Realm в списке SwiftUI? - PullRequest
2 голосов
/ 23 июня 2019

Мне удалось сохранить данные в базе данных Realm, но я не смог показать результаты в SwiftUI List.

Я знаю, что у меня есть данные и у меня нет проблем с печатью результатов вконсоль.

Есть ли способ преобразовать Realm Result в формат, который может быть отображен на 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

Возможно, некоторые части кода не выполняютсясмысл, потому что я пытался несколько подходов, чтобы увидеть, будет ли что-нибудь работать.

Эта строка, например, будет отображать результат в представлении списка.

return results.first!.name

Если я просто возвращаю результаты, в представлении текста списка ничего не отображается.

Как я прокомментировал ниже, я попытаюсь использовать подход ForEach, когда у меня будет время.Это выглядит многообещающе.

1 Ответ

4 голосов
/ 23 июня 2019

Данные, которые вы передаете в List или ForEach, должны соответствовать протоколу Identifiable.

Либо вы принимаете его в своих моделях Царства, либо используете метод .identified(by:).


Несмотря на это, View не будет перезагружаться при изменении данных.

Вы можете обернуть Results и сделать его BindableObject, чтобы представление могло обнаружить изменения и перезагрузить себя:

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

    let didChange = PassthroughSubject<Void, Never>()

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

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

    func lateInit() {
        token = results.observe { _ in
            self.didChange.send(())
        }
    }

    deinit {
        token.invalidate()
    }
}

И используйте это как:

struct ContentView : View {

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

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

}
...