在我们的应用中,我们使用UserService
,它是一个ObservableObject
,并作为环境传递。打开一个同步领域,并使用灵活的同步获取应用用户(RealmObject)。
当更新用户属性时,比如用户名,视图不会被重绘。这与我的预期不符,因为UserService
包含一个@Published
属性,用户(正在编辑)存储在其中。在数据库上,它清楚地显示正在编辑的属性,但是视图不会被重绘,只有当重新启动应用程序时,新属性才会显示。
让UserService
对象负责所有与用户相关的逻辑(存储用户对象(对它的引用),包含要更新的函数,......)并使用它在整个视图中显示该用户的活动数据的最佳方法是什么?
下面是一个MRE(省略登录逻辑以降低复杂性):
import SwiftUI
import RealmSwift
class UserService2: ObservableObject {
var realm: Realm
@Published var ownUser: User
var userNotificationToken: NotificationToken?
init(realm: Realm, ownUser: User) {
self.realm = realm
self.ownUser = ownUser
userNotificationToken = ownUser.observe { change in
print(change) // just to see that the user object is actually live and being updated...
}
}
func changeName(newName: String) {
do {
try self.realm.write {
self.ownUser.userName = newName
}
} catch {
print("error")
}
}
}
struct TestView: View {
@EnvironmentObject var userService: UserService2
var body: some View {
VStack {
Text(userService.ownUser.userName ?? "no name")
Button {
userService.changeName(newName: Date().description)
} label: {
Text("change name")
}
}
}
}
struct ContentView: View {
var realm: Realm? = nil
init() {
let flexSyncConfig = app.currentUser!.flexibleSyncConfiguration(initialSubscriptions: { subs in
subs.append(
QuerySubscription<User>(name: "ownUserQuery") {
$0._id == "123"
})
})
do {
let realm = try Realm(configuration: flexSyncConfig)
self.realm = realm
} catch {
print("sth went wrong")
}
}
var body: some View {
if let realm = realm, let ownUser = realm.objects(User.self).where( { $0._id == "123" } ).first {
TestView()
.environmentObject(UserService2(realm: realm, ownUser: ownUser))
} else {
ProgressView()
}
}
}
User
对象如下所示
import Foundation
import RealmSwift
class User: Object, ObjectKeyIdentifiable {
@Persisted(primaryKey: true) var _id = UUID().uuidString
@Persisted var userName: String?
convenience init(_id: String? = nil, userName: String? = nil) {
self.init()
if let _id = _id {
self._id = _id
}
self.userName = userName
}
}
我想我可以使用realm来观察对象的变化,并以某种方式强制视图刷新,但我会发现使用现有的方法来观察变化并在需要时使用@Published
来重绘视图要干净得多...
P. P. S.这个用户对象是在服务器上创建的,当有人进行身份验证时使用触发器。不过,我假设这与这个问题并不真正相关。
1条答案
按热度按时间rta7y2nd1#
这里的问题是引用类型作为“事实来源”的用法。
ObservableObject
和SwiftUI视图使用合并发布程序来了解何时刷新。@Published
值仅在其 Package 值“更改”时发送ObservableObject
的.objectWillChange
发布者。在此上下文中,“更改”意味着它被替换。因此,此处首选值类型,因为如果更改其中一个属性,则整个对象将被替换。引用类型不会发生这种情况。此处有多种可能的解决方案:
User
类更改为struct(此处可能不需要,因为此对象实现了Realm).objectWillChange.send()
方法ownUser
变量,而要用包含新信息的新变量替换它。