如何在 SwiftUI 中使用 Realm

Posted

技术标签:

【中文标题】如何在 SwiftUI 中使用 Realm【英文标题】:How to use Realm with SwiftUI 【发布时间】:2019-06-19 23:50:44 【问题描述】:

我一直在试图弄清楚如何将 Realm 与 SwiftUI 一起使用。问题是 SwiftUI 和 Realm 都有一个 List 类型。当您将 SwiftUI 导入您的 Realm 模型以使该类成为 BindableObject 并尝试创建 Realm List 属性时,会出现错误。

是否可以在 SwiftUI 中使用 Realm 对象模型的实例并使其成为 BindableObject?

【问题讨论】:

【参考方案1】:

当然,很简单,使用模块标识符作为前缀:

let members = RealmSwift.List<Member>()

现在到问题的第二部分。将 Realm 对象(或列表或结果集)封装在 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)
        )
    

如果您使用 @ObjectBinding@EnvironmentObjectDBData 实例“链接”到 SwiftUI View,则 UI 将被刷新,posts 的新值(在我们的示例中)将为每次底层领域更改时都可用。

【讨论】:

您能否展示一个使用最新 SwiftUI 和 Xcode 11 Beta 7 的示例? 这似乎会在您删除对象时导致崩溃【参考方案2】:

@JustinMiller 我创建了一个 ChannelsData 类,用于监听 Realm 集合中聊天频道的变化。然后,我通过在我的视图中将 ChannelsData 设置为 @EnvironmentObject 来更新 UI。以下是在 Xcode 11 GM Seed 中对我有用的内容:

final class ChannelsData: ObservableObject 
    @Published var channels: [Channel]
    private var channelsToken: NotificationToken?

// Grab channels from Realm, and then activate a Realm token to listen for changes.
init() 
    let realm = try! Realm()
    channels = Array(realm.objects(Channel.self)) // Convert Realm results object to Array
    activateChannelsToken()


private func activateChannelsToken() 
    let realm = try! Realm()
    let channels = realm.objects(Channel.self)
    channelsToken = channels.observe  _ in
        // When there is a change, replace the old channels array with a new one.
        self.channels = Array(channels) 
    


deinit 
    channelsToken?.invalidate()

然后我使用@EnvironmentObject 为我的视图抓取频道:

struct ChannelsContainerView: View 

    @EnvironmentObject var channelsData: ChannelsData

    var body: some View 
        List(channelsData.channels.indexed(), id: \.1.id)  index, _ in
            NavigationLink(destination: ChatView()) 
                ChannelRow(channel: self.$channelsData.channels[index])
            
        
    

不用担心 List 中的 indexed() 函数。但如果你好奇,它来自 Majid 在这里创建灵活的 SwiftUI 数据存储类的巧妙方法:https://mecid.github.io/2019/09/04/modeling-app-state-using-store-objects-in-swiftui/

如果您从另一个视图进入该视图,请务必将 .environmentObject(ChannelsData()) 添加到您的视图链接(以及您的预览中),否则它将不起作用。

【讨论】:

不确定您的解决方案是否有效 - 尝试删除项目 - 似乎崩溃了。 对!当 @Published 属性将更新时,SwiftUI 会将更改发送到 View。当收到 RealmCollectionChange> 通知时,Results 已经更新,因为它报告“实时”更改;因此,由于索引超出范围,删除时会发生致命错误。我在这里更详细地解决解决方案/问题:***.com/a/62629301/3739895

以上是关于如何在 SwiftUI 中使用 Realm的主要内容,如果未能解决你的问题,请参考以下文章

如何从 SwiftUI 和 Realm 中另一个列表中的对象中添加和删除列表中的对象

如何从 SwiftUI 列表和领域中删除数据

在 SwiftUI 列表中呈现来自 Realm 的数据的正确方法是啥

在 SwiftUI 列表中呈现来自 Realm 的数据的正确方法是啥

如何在 SwiftUI 列表中显示领域结果?

SwiftUI 中的领域:UI 中仅偶尔保存对象的实时文本