如何在 SwiftUI 中使用 Realm
How to use Realm with SwiftUI
我一直在努力弄清楚如何将 Realm 与 SwiftUI 结合使用。问题是 SwiftUI 和 Realm 都有一个 List 类型。当您将 SwiftUI 导入 Realm 模型以使 class 成为 BindableObject 并尝试创建 Realm List 属性 时出现错误。
是否可以使用 Realm 对象模型的实例并使其成为 SwiftUI 中的 BindableObject?
当然,这很简单,像这样使用模块标识符作为前缀:
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)
})
}
}
如果你 "link" 一个 DBData
实例到 SwiftUI View
通过使用 @ObjectBinding
或 @EnvironmentObject
UI 将被刷新并且 posts
的新值(在我们这里的示例中)将在每次基础领域更改时可用。
@JustinMiller 我创建了一个 ChannelsData class,我用它来监听来自 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 数据存储的巧妙方法 class:https://mecid.github.io/2019/09/04/modeling-app-state-using-store-objects-in-swiftui/
如果您是从另一个视图进入视图,请务必将 .environmentObject(ChannelsData()) 添加到您的视图 link(以及您的预览中),否则它将不起作用.
我一直在努力弄清楚如何将 Realm 与 SwiftUI 结合使用。问题是 SwiftUI 和 Realm 都有一个 List 类型。当您将 SwiftUI 导入 Realm 模型以使 class 成为 BindableObject 并尝试创建 Realm List 属性 时出现错误。
是否可以使用 Realm 对象模型的实例并使其成为 SwiftUI 中的 BindableObject?
当然,这很简单,像这样使用模块标识符作为前缀:
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)
})
}
}
如果你 "link" 一个 DBData
实例到 SwiftUI View
通过使用 @ObjectBinding
或 @EnvironmentObject
UI 将被刷新并且 posts
的新值(在我们这里的示例中)将在每次基础领域更改时可用。
@JustinMiller 我创建了一个 ChannelsData class,我用它来监听来自 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 数据存储的巧妙方法 class:https://mecid.github.io/2019/09/04/modeling-app-state-using-store-objects-in-swiftui/
如果您是从另一个视图进入视图,请务必将 .environmentObject(ChannelsData()) 添加到您的视图 link(以及您的预览中),否则它将不起作用.