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

Swift中如何在URL请求返回前阻止App启动至初始视图控制器?

问题分析

你这段代码的核心问题有两个:

  1. fetchUser是异步网络请求,didFinishLaunchingWithOptions会直接返回true,APP随即启动初始视图控制器,此时请求大概率还没完成,fetchBaseData自然是nil。
  2. 你每次调用APICaller()都是创建新实例,回调里给新实例的fetchBaseData赋值,初始视图控制器里的APICaller实例根本拿不到这个值。
解决方案

第一步:把APICaller改成单例(必做)

只有用单例才能保证赋值和读取的是同一个实例的属性:

class APICaller {
    static let shared = APICaller() // 全局单例
    var fetchBaseData: BaseData? // 替换成你的实际数据类型

    func fetchUser(completionHandler: @escaping (BaseData?, Error?) -> Void) {
        // 你的网络请求逻辑
    }
}

方案一:在AppDelegate中等待请求完成(适合iOS12及以下)

用DispatchGroup等待请求结束,注意要设置超时时间,避免APP长时间卡顿:

func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    let group = DispatchGroup()
    var fetchedData: BaseData?

    group.enter()
    APICaller.shared.fetchUser { baseData, error in
        fetchedData = baseData
        group.leave()
    }

    // 等待请求完成,超时时间设为10秒(可按需调整)
    let waitResult = group.wait(timeout: .now() + 10)
    if waitResult == .success, let data = fetchedData {
        APICaller.shared.fetchBaseData = data
    }

    return true
}

⚠️ 注意:这种方式会阻塞主线程,APP启动屏会停留到请求完成,建议配合启动屏优化用户体验。

方案二:iOS13+用SceneDelegate延迟加载根控制器(推荐)

这种方式不会阻塞主线程,启动屏会正常显示,请求完成后再加载初始视图控制器:

func scene(_ scene: UIScene, willConnectTo session: UISceneSession, options connectionOptions: UIScene.ConnectionOptions) {
    guard let windowScene = (scene as? UIWindowScene) else { return }
    let window = UIWindow(windowScene: windowScene)
    self.window = window

    APICaller.shared.fetchUser { baseData, error in
        if let data = baseData {
            APICaller.shared.fetchBaseData = data
        }
        // 请求完成后再初始化并显示根控制器
        let rootVC = YourInitialViewController() // 替换成你的初始VC类名
        window.rootViewController = UINavigationController(rootViewController: rootVC)
        window.makeKeyAndVisible()
    }
}

方案三:在初始视图控制器中处理数据加载

如果允许初始视图控制器先显示,再等待数据更新UI,可以这么做:

class YourInitialViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // 显示加载指示器
        let loadingIndicator = UIActivityIndicatorView(style: .large)
        loadingIndicator.center = view.center
        loadingIndicator.startAnimating()
        view.addSubview(loadingIndicator)

        // 检查数据是否已加载
        if let data = APICaller.shared.fetchBaseData {
            updateUI(with: data)
            loadingIndicator.stopAnimating()
        } else {
            // 重新请求数据
            APICaller.shared.fetchUser { [weak self] baseData, error in
                DispatchQueue.main.async {
                    loadingIndicator.stopAnimating()
                    guard let data = baseData else {
                        // 这里处理请求失败的逻辑,比如显示错误提示
                        return
                    }
                    APICaller.shared.fetchBaseData = data
                    self?.updateUI(with: data)
                }
            }
        }
    }

    private func updateUI(with data: BaseData) {
        // 根据数据更新你的UI
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.11 22:15:17