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

SwiftUI结合Firebase获取用户数据及跨页传递问题排查

问题分析与解决方案

当前代码的核心问题

  • ObservableObject缺少@Published属性:UserDataFile没有定义存储用户数据的可发布属性,获取到数据后无法触发视图更新。
  • 文档路径错误:用固定的"ProfileImages"作为文档ID,应该使用当前登录用户的UID(Auth.auth().currentUser?.uid),每个用户对应自己的Firestore专属文档。
  • 重复创建ObservableObject实例:ProfileHeader和AccountView各自新建UserDataFile,无法共享数据,跨页面传递应该用环境对象共享同一个实例。
  • 数据未绑定到视图:获取到数据后仅打印,没有赋值到属性,视图无法展示数据。
  • 错误处理缺失:Firestore请求的error未处理,无法排查请求失败原因。
  • NavigationView嵌套错误:多个视图嵌套NavigationView,SwiftUI中通常只需要一个根NavigationView。
  • 冗余代码:AccountView中重复实现了FetchUser方法,应该复用UserDataFile中的方法。

改写后的完整代码

1. 修正ObservableObject类(UserDataFile)

import SwiftUI
import FirebaseAuth
import FirebaseFirestore

// 定义用户数据模型,对应Firestore中的字段
struct UserModel: Codable {
    var uid: String
    var name: String?
    var email: String?
    // 根据你的实际需求添加其他字段
}

class UserDataFile: ObservableObject {
    // 用@Published修饰,数据变化时自动通知视图更新
    @Published var currentUser: UserModel?
    @Published var isLoading = false
    @Published var errorMessage: String?
    
    func fetchUser() {
        guard let uid = Auth.auth().currentUser?.uid else {
            errorMessage = "未检测到登录用户"
            return
        }
        
        isLoading = true
        errorMessage = nil
        
        let db = Firestore.firestore()
        // 使用用户UID作为文档ID,确保每个用户访问自己的专属数据
        let docRef = db.collection("user").document(uid)
        
        docRef.getDocument { [weak self] document, error in
            guard let self = self else { return }
            self.isLoading = false
            
            if let error = error {
                self.errorMessage = "获取用户数据失败: \(error.localizedDescription)"
                print(error.localizedDescription)
                return
            }
            
            guard let document = document, document.exists, let data = document.data() else {
                self.errorMessage = "用户文档不存在"
                print("Document does not exist")
                return
            }
            
            // 解析Firestore数据到UserModel
            do {
                self.currentUser = try JSONDecoder().decode(UserModel.self, from: JSONSerialization.data(withJSONObject: data))
            } catch {
                self.errorMessage = "数据解析失败: \(error.localizedDescription)"
                print(error.localizedDescription)
            }
        }
    }
}

2. 根视图注入环境对象

在App的根视图创建一次UserDataFile实例,通过环境对象让所有子视图共享:

@main
struct YourAppName: App {
    @StateObject private var userData = UserDataFile()
    
    var body: some Scene {
        WindowGroup {
            NavigationView {
                ProfileHeader()
            }
            // 注入环境对象,所有子视图都能获取到同一个实例
            .environmentObject(userData)
        }
    }
}

3. 修改ProfileHeader视图

struct ProfileHeader: View {
    // 通过@EnvironmentObject获取共享的UserDataFile实例
    @EnvironmentObject var userData: UserDataFile
    
    var body: some View {
        // 移除多余的NavigationView,根视图已包含
        Button {
        } label: {
            NavigationLink(destination: AccountView()) {
                Text("Account")
                    .foregroundColor(.white)
            }
        }
        .onAppear {
            // 页面出现时触发用户数据获取
            userData.fetchUser()
        }
    }
}

4. 修改AccountView视图

struct AccountView: View {
    // 通过@EnvironmentObject获取共享的UserDataFile实例
    @EnvironmentObject var userData: UserDataFile
    
    var body: some View {
        ScrollView {
            VStack(spacing: 20) {
                // 根据状态展示不同内容
                if userData.isLoading {
                    ProgressView("加载中...")
                } else if let error = userData.errorMessage {
                    Text(error)
                        .foregroundColor(.red)
                } else if let user = userData.currentUser {
                    Text("用户ID: \(user.uid)")
                    if let name = user.name {
                        Text("用户名: \(name)")
                    }
                    if let email = user.email {
                        Text("邮箱: \(email)")
                    }
                } else {
                    Text("未获取到用户数据")
                }
                
                Button {
                    // 点击按钮重新获取数据
                    userData.fetchUser()
                } label: {
                    Text("重新加载")
                        .foregroundColor(.red)
                        .font(.largeTitle)
                        .fontWeight(.bold)
                }
            }
            .padding()
        }
    }
}

关键说明

  • @Published属性:必须用@Published修饰存储数据的属性,确保数据变化时ObservableObject能发送通知,触发视图更新。
  • 共享实例:通过environmentObject在根视图注入UserDataFile,子视图用@EnvironmentObject获取,实现跨页面数据同步。
  • 正确的文档路径:使用用户UID作为文档ID是Firestore存储用户数据的标准做法,确保数据隔离。
  • 错误与状态处理:加入加载状态、错误提示,方便调试和提升用户体验;用Codable解析数据,避免手动处理字典的繁琐。
  • NavigationView优化:仅在根视图保留一个NavigationView,避免嵌套导致的布局异常。

内容的提问来源于stack exchange,提问作者user21359551

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.27 04:37:47