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

iOS开发:如何在跳转至其他VC前预加载数据?

这个场景我太熟悉了——想通过预加载提升用户体验,但快速跳转时的竞态问题确实容易踩坑。咱们来拆解几个靠谱的解决方案:

核心解决思路:给数据加载加状态管理 + 回调机制

问题本质是异步加载的不确定性,所以我们需要在单例里明确数据的加载状态,并让目标VC能监听加载结果,不管是已经加载完成、正在加载还是加载失败,都能做出对应处理。

1. 改造你的单例,加入状态和回调

先给MySingleton扩展状态枚举、回调队列,确保加载逻辑的原子性:

class MySingleton {
    static let shared = MySingleton()
    
    // 定义加载状态,覆盖所有可能的情况
    enum UserLoadState {
        case idle, loading, loaded, failed(Error)
    }
    
    private(set) var user: User?
    private(set) var userLoadState: UserLoadState = .idle
    // 存储等待加载完成的回调
    private var pendingCallbacks: [(Result<User, Error>) -> Void] = []
    
    // 触发用户数据加载的方法,防止重复调用
    func loadUser() {
        guard userLoadState == .idle else { return }
        userLoadState = .loading
        
        // 模拟数据库异步读取(替换成你的实际数据库逻辑)
        DispatchQueue.global(qos: .userInitiated).async {
            do {
                let fetchedUser = try YourDatabase.fetchCurrentUser()
                DispatchQueue.main.async {
                    self.user = fetchedUser
                    self.userLoadState = .loaded
                    self.notifyAllCallbacks(.success(fetchedUser))
                }
            } catch {
                DispatchQueue.main.async {
                    self.userLoadState = .failed(error)
                    self.notifyAllCallbacks(.failure(error))
                }
            }
        }
    }
    
    // 通知所有等待的回调
    private func notifyAllCallbacks(_ result: Result<User, Error>) {
        pendingCallbacks.forEach { $0(result) }
        pendingCallbacks.removeAll() // 清空队列,避免重复回调
    }
    
    // 对外暴露的监听方法,不管数据是否加载完成都能拿到结果
    func whenUserLoaded(completion: @escaping (Result<User, Error>) -> Void) {
        switch userLoadState {
        case .loaded where user != nil:
            // 已经加载完成,直接返回结果
            completion(.success(user!))
        case .failed(let error):
            // 加载失败,返回错误
            completion(.failure(error))
        case .loading, .idle:
            // 正在加载或未开始,加入回调队列
            pendingCallbacks.append(completion)
            // 如果还没开始加载,自动触发
            if userLoadState == .idle {
                loadUser()
            }
        }
    }
}

2. 在User VC里优雅处理数据展示

不管用户什么时候跳转到User VC,都能根据加载状态展示对应的UI:

class UserVC: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        setupUserInterface()
    }
    
    private func setupUserInterface() {
        // 先显示加载状态(比如占位符、活动指示器)
        showLoadingPlaceholder()
        
        // 监听用户数据加载结果
        MySingleton.shared.whenUserLoaded { [weak self] result in
            guard let self = self else { return }
            switch result {
            case .success(let user):
                self.renderUserInfo(user)
            case .failure(let error):
                self.showLoadError(error)
            }
        }
    }
    
    // 显示加载中的UI
    private func showLoadingPlaceholder() {
        // 比如:activityIndicator.startAnimating(),显示"加载中..."文本
    }
    
    // 渲染用户数据到UI
    private func renderUserInfo(_ user: User) {
        // 比如:nameLabel.text = user.name,隐藏活动指示器
    }
    
    // 处理加载失败的情况
    private func showLoadError(_ error: Error) {
        // 比如:弹出Alert提示加载失败,提供重试按钮
        let alert = UIAlertController(title: "加载失败", message: error.localizedDescription, preferredStyle: .alert)
        alert.addAction(UIAlertAction(title: "重试", style: .default) { _ in
            self.setupUserInterface()
        })
        alert.addAction(UIAlertAction(title: "取消", style: .cancel))
        present(alert, animated: true)
    }
}

3. 可选优化:在Home VC提前触发预加载

在Home VC的合适时机(比如viewDidAppear)提前触发加载,进一步提升跳转体验:

class HomeVC: UIViewController {
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        // 提前预加载用户数据,用户跳转时大概率已经加载完成
        MySingleton.shared.loadUser()
    }
}

关键注意点

  • 用[weak self]避免闭包导致的循环引用
  • 确保loadUser方法有状态判断,防止重复发起数据库请求
  • 不要忽略加载失败的场景,给用户明确的反馈和重试机会

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.19 08:26:19