SwiftUI如何在App启动前初始化@StateObject变量?
解决SwiftUI启动时因Firebase加载延迟导致的页面闪屏问题
核心问题分析
你的问题出在没有区分「数据正在加载」和「确实没有数据」两种状态:UserProfileService初始化时异步请求Firebase数据,hasData()一开始返回false,导致先显示注册页,等数据加载完成后才切换到主页面,出现闪屏。
解决方案
给UserProfileService增加加载状态标记,先显示加载视图,等Firebase数据请求完成后,再根据实际数据状态跳转页面。
1. 修改UserProfileService,添加加载状态和异步数据获取方法
把原来在init里的异步逻辑抽出来,用@Published属性跟踪加载状态:
import FirebaseAuth import FirebaseFirestore class UserProfileService: ObservableObject { @Published var isLoading = true // 标记是否正在加载数据 @Published private var userData: UserData? // 替换成你的用户数据模型 // 判断是否有有效用户数据 func hasData() -> Bool { return userData != nil } // 异步获取Firebase用户数据 func fetchUserData() async { isLoading = true defer { isLoading = false } // 请求结束后无论成功失败都标记加载完成 // 先检查当前是否有已认证用户 guard let currentUser = Auth.auth().currentUser else { return } do { // 从Firestore获取用户数据 let docSnapshot = try await Firestore.firestore() .collection("users") .document(currentUser.uid) .getDocument() self.userData = try docSnapshot.data(as: UserData.self) } catch { print("加载用户数据失败: \(error.localizedDescription)") } } }
2. 更新App入口逻辑,先显示加载视图
利用SwiftUI的.task修饰符在视图启动时执行异步数据请求,根据isLoading和hasData()的状态切换页面:
@main struct myApp: App { @StateObject private var userProfileService = UserProfileService() var body: some Scene { WindowGroup { Group { // 加载中:显示启动屏或进度指示器 if userProfileService.isLoading { ProgressView("加载中...") .scaleEffect(1.5) .foregroundColor(.blue) } // 无有效数据:显示注册页 else if !userProfileService.hasData() { NavigationView { phoneRegistrationView() } } // 有有效数据:显示主页面 else { mainTabBarView() } } .environmentObject(userProfileService) .task { // 页面启动时异步加载用户数据 await userProfileService.fetchUserData() } } } }
为什么这个方案有效
- 明确区分了「加载中」「无数据」「有数据」三种状态,避免了因异步延迟导致的错误页面跳转。
.task修饰符会在视图初始化后自动执行异步任务,且生命周期与视图绑定,适合启动时的一次性数据请求。defer语句确保无论数据请求成功或失败,isLoading都会被设置为false,不会一直停留在加载状态。
内容的提问来源于stack exchange,提问作者GianlucaA
相关产品推荐
相关产品推荐

