SwiftUI使用Firebase存用户数据时模型变更跳转根视图问题咨询
问题原因
- 加载状态逻辑错误:你使用
functionResult作为加载/主视图切换的控制变量,每次用户数据更新的回调都会执行toggle()操作。首次拉取用户数据后functionResult变为true显示主视图,后续用户数据变更触发回调时,functionResult会被切换为false,界面切回加载屏,回调完成后又变回true重新渲染主视图,视觉上就出现了跳转到根视图的现象。 - 状态存储位置不合理:用户数据
userState和加载状态都定义在ContentView的@State属性中,每次用户数据更新都会触发ContentView整体重绘。你使用的自定义UIKitTabView如果没有绑定外部状态保存选中的tab索引,重绘后会自动回到第一个tab,也会出现类似跳根的表现。 - 数据库监听范围过大:你监听了整个
users节点的.childAdded事件,任意用户的数据变更都会触发你的回调逻辑,不必要的高频触发进一步加剧了上述问题。
解决方案
- 将用户数据、加载状态都迁移到全局的
SessionStore(ObservableObject)中作为@Published属性管理,避免ContentView局部状态反复变更导致的整体重绘。 - 缩小Firebase监听范围,仅监听当前登录用户的节点数据,不要监听全量用户节点。如果不需要实时同步用户数据,改用
observeSingleEvent单次拉取数据即可。 - 移除无用的
functionResult状态变量,改用独立的加载状态变量控制加载屏和主视图的切换,避免每次拉取数据都翻转状态。 - 给自定义
UIKitTabView添加选中tab的@Binding属性,持久化保存当前选中的tab索引,避免视图重绘时自动回到首tab。
代码示例
1. 修改SessionStore
class SessionStore: ObservableObject { // 保留原有已实现的属性和方法,新增以下内容 @Published var currentUser: UserData? @Published var isLoadingUser = true func observeCurrentUser() { guard let uid = session?.uid else { return } // 仅监听当前登录用户的节点 ref.child("users").child(uid).observe(.value) { [weak self] snapshot in guard let self = self, let dictionary = snapshot.value as? [String: AnyObject] else { return } var user = UserData() user.email = (dictionary["email"] as! String) user.name = (dictionary["name"] as! String) user.firstname = (dictionary["firstname"] as! String) user.lastname = (dictionary["lastname"] as! String) user.type = (dictionary["type"] as! String) user.uid = (dictionary["uid"] as! String) user.profileImageUrl = (dictionary["profileImageUrl"] as! String) user.id = snapshot.key user.fcmToken2 = (dictionary["fcmToken"] as! String) self.currentUser = user self.isLoadingUser = false } } }
2. 修改ContentView
struct ContentView: View { @EnvironmentObject var session: SessionStore var body: some View { VStack { if session.session == nil { HomeView() } else { if session.isLoadingUser { DelayedLaunchScreen(user: session.currentUser ?? UserData()) } else if let user = session.currentUser { MainView(user: user) } } } .onAppear { session.listen() session.observeCurrentUser() } } }
内容的提问来源于stack exchange,提问作者Pakenas
相关产品推荐
相关产品推荐

