• 首页 首页 icon
  • 工具库 工具库 icon
    • IP查询 IP查询 icon
  • 内容库 内容库 icon
    • 快讯库 快讯库 icon
    • 精品库 精品库 icon
    • 问答库 问答库 icon
  • 更多 更多 icon
    • 服务条款 服务条款 icon

在 SwiftUI 列表显示 Realm 结果?

用户头像
it1352
帮助1

问题说明

我已经能够在 Realm 数据库中保存数据,但无法在 SwiftUI List 中显示结果.

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.

有没有办法将 Realm Result 转换成可以在 SwiftUI List 上显示的格式?

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.

正如我在下面评论的那样,我会在有时间的时候尝试 ForEach 方法.这看起来很有希望.

As I have commented below I will attempt the ForEach approach when I have time. That looks promising.

正确答案

#1

您在 ListForEach 中传递的数据必须符合 Identifiable 协议.

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

要么在 Realm 模型中采用它,要么使用 .identified(by:) 方法.

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

即便如此,如果数据发生变化,View 也不会重新加载.

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

您可以包装 Results 并使其成为 BindableObject,以便视图可以检测更改并重新加载自身:

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

然后像这样使用它:

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

}

这篇好文章是转载于:学新通技术网

  • 版权申明: 本站部分内容来自互联网,仅供学习及演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,请提供相关证据及您的身份证明,我们将在收到邮件后48小时内删除。
  • 本站站名: 学新通技术网
  • 本文地址: /reply/detail/tanhcfefig
系列文章
更多 icon
同类精品
更多 icon
继续加载