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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.01 22:40:24