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

VIPER架构下网络请求发起及跨页面结果通知方案咨询

我来帮你梳理这两个VIPER架构下的实践问题,结合实际项目经验给你具体的实现思路和示例:

在VIPER架构中,单个页面内发起网络请求并获取结果的流程

VIPER的核心是职责分离,所以网络请求的流程会严格按照View → Presenter → Interactor → Presenter → View的链路走,每个角色只做自己的事:

  • View层触发请求:比如用户点击"获取数据"按钮,View(通常是ViewController)只负责把交互事件传递给Presenter,调用类似presenter.initiateDataFetch()的方法,不做任何业务逻辑处理。
  • Presenter层协调调度:Presenter收到请求后,先通知View显示加载状态(比如view.showLoadingIndicator()),然后调用Interactor对应的网络请求方法,比如interactor.fetchTargetData(with: params)。Presenter在这里可以做参数合法性校验,避免无效请求。
  • Interactor层执行核心逻辑:Interactor是业务逻辑和数据获取的核心,这里会调用你的网络请求function。为了把结果回传给Presenter,通常会定义一个回调协议(或者用闭包、Combine),比如:
    // Interactor的回调协议
    protocol DataFetchDelegate: AnyObject {
        func didFetchDataSuccess(_ data: TargetEntity)
        func didFetchDataFailure(_ error: Error)
    }
    
    class DataInteractor {
        weak var delegate: DataFetchDelegate?
    
        func fetchTargetData(params: [String: Any]) {
            // 调用你的耗时网络请求function
            NetworkService.shared.requestData(params: params) { [weak self] result in
                switch result {
                case .success(let rawData):
                    // 这里还可以做数据解析,把原始响应转成Entity
                    let entity = TargetEntity.parse(from: rawData)
                    self?.delegate?.didFetchDataSuccess(entity)
                case .failure(let error):
                    self?.delegate?.didFetchDataFailure(error)
                }
            }
        }
    }
    
  • Interactor回调结果给Presenter:请求完成后,Interactor通过协议回调把Entity或错误传给Presenter。
  • Presenter更新View:Presenter拿到结果后,把Entity转换成View需要的ViewModel(比如把日期格式化成字符串、拼接显示文本),然后调用View的方法更新UI:成功就调用view.displayData(viewModel: viewModel),失败就调用view.showError(message: error.localizedDescription),同时隐藏加载状态。
应用启动后提前发起耗时请求,通知Presenter结果的实现方案

要实现启动后预加载数据,核心是在启动阶段发起请求、存储结果、在目标页面Presenter中获取/监听结果,具体步骤如下:

1. 选择启动时机发起请求

不要直接在AppDelegate/SceneDelegate里写请求逻辑,封装到一个全局的预加载Interactor里:

class PreloadInteractor {
    func startCriticalDataPreload() {
        // 调用你的耗时请求function
        HeavyDataService.shared.fetchCriticalData { result in
            switch result {
            case .success(let data):
                // 存储结果到全局数据容器
                AppGlobalStore.shared.criticalPreloadedData = data
                AppGlobalStore.shared.isPreloadCompleted = true
                // 发送通知告知所有监听者请求完成
                NotificationCenter.default.post(name: .preloadCompleted, object: nil)
            case .failure(let error):
                AppGlobalStore.shared.preloadError = error
                AppGlobalStore.shared.isPreloadCompleted = true
                NotificationCenter.default.post(name: .preloadFailed, object: error)
            }
        }
    }
}

// 在AppDelegate中启动预加载
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
    PreloadInteractor().startCriticalDataPreload()
    return true
}

2. 存储预加载结果

用一个全局单例存储结果和状态,方便后续Presenter访问:

class AppGlobalStore {
    static let shared = AppGlobalStore()
    var criticalPreloadedData: CriticalEntity?
    var preloadError: Error?
    var isPreloadCompleted = false
}

// 定义通知名称
extension Notification.Name {
    static let preloadCompleted = Notification.Name("PreloadCompleted")
    static let preloadFailed = Notification.Name("PreloadFailed")
}

3. 通知Presenter结果的两种常用方式

  • 方式一:依赖注入(推荐)
    当用户进入目标页面时,Presenter初始化时注入AppGlobalStore,直接检查预加载状态:
    class TargetPresenter {
        weak var view: TargetViewProtocol?
        private let globalStore: AppGlobalStore
    
        init(globalStore: AppGlobalStore = .shared) {
            self.globalStore = globalStore
            checkPreloadedData()
        }
    
        private func checkPreloadedData() {
            if globalStore.isPreloadCompleted {
                if let data = globalStore.criticalPreloadedData {
                    let viewModel = CriticalViewModel(from: data)
                    view?.displayPreloadedData(viewModel)
                } else if let error = globalStore.preloadError {
                    view?.showPreloadError(error.localizedDescription)
                }
            } else {
                // 预加载未完成,显示加载状态并监听通知
                view?.showLoading()
                NotificationCenter.default.addObserver(self, selector: #selector(handlePreloadUpdate), name: .preloadCompleted, object: nil)
                NotificationCenter.default.addObserver(self, selector: #selector(handlePreloadUpdate), name: .preloadFailed, object: nil)
            }
        }
    
        @objc private func handlePreloadUpdate(notification: Notification) {
            view?.hideLoading()
            checkPreloadedData()
            // 移除监听避免内存泄漏
            NotificationCenter.default.removeObserver(self)
        }
    }
    
  • 方式二:Combine/RxSwift响应式监听
    如果项目用了响应式框架,可以把预加载状态做成可观察对象,Presenter订阅后自动收到更新,代码会更简洁,避免手动管理通知监听。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.22 08:00:16