You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

SwiftUI使用Firebase存用户数据时模型变更跳转根视图问题咨询

问题原因
  1. 加载状态逻辑错误:你使用functionResult作为加载/主视图切换的控制变量,每次用户数据更新的回调都会执行toggle()操作。首次拉取用户数据后functionResult变为true显示主视图,后续用户数据变更触发回调时,functionResult会被切换为false,界面切回加载屏,回调完成后又变回true重新渲染主视图,视觉上就出现了跳转到根视图的现象。
  2. 状态存储位置不合理:用户数据userState和加载状态都定义在ContentView的@State属性中,每次用户数据更新都会触发ContentView整体重绘。你使用的自定义UIKitTabView如果没有绑定外部状态保存选中的tab索引,重绘后会自动回到第一个tab,也会出现类似跳根的表现。
  3. 数据库监听范围过大:你监听了整个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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 13:27:04