You need to enable JavaScript to run this app. VIPER架构下UICollectionView的didSelectItemAt逻辑应存放于哪一层?
优惠活动
大模型
产品
解决方案
定价
更多

VIPER架构下UICollectionView的didSelectItemAt逻辑应存放于哪一层?

VIPER架构下didSelectItemAt事件的逻辑分层方案

所有逻辑都不应该直接写在View层的didSelectItemAt方法里,不同类型的逻辑对应VIPER的不同分层:

  • 页面跳转(push新ViewController):由 Router层 负责实现,Presenter层触发调用
  • 网络请求/业务数据处理:由 Interactor层 负责实现,Presenter层触发调用
  • ViewModel不属于标准VIPER架构的组件,如果你是混合了MVVM+VIPER的架构,ViewModel仅负责为View提供绑定用的格式化数据,不处理点击事件的业务逻辑、跳转逻辑

具体实现流程

  • 第一步:View层的didSelectItemAt仅负责将点击事件和对应的下标传递给Presenter,不做任何业务处理
    func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
        presenter?.didSelectCert(at: indexPath.item, status: getCertStatus())
    }
    
  • 第二步:Presenter层接收事件后做逻辑调度
    • 如果点击后需要先请求数据再跳转:Presenter调用Interactor的请求方法,等Interactor返回结果后,再调用Router的跳转方法,把需要传递的数据传给Router
    • 如果点击后不需要请求数据直接跳转:Presenter直接从自己持有的数据源里拿到对应的Cert模型,调用Router的跳转方法
      示例代码:
    // Presenter层方法
    func didSelectCert(at index: Int, status: CertStatus) {
        guard let cert = certList[safe: index] else { return }
        // 场景1:需要先请求详情数据
        interactor?.fetchCertDetail(certId: cert.id)
        
        // 场景2:直接跳转不需要请求数据
        // router?.pushToCertDetailPage(cert: cert)
    }
    
    // 接收Interactor的请求成功回调
    func didFetchCertDetailSuccess(detail: CertDetail) {
        router?.pushToCertDetailPage(detail: detail)
    }
    
    // 接收Interactor的请求失败回调
    func didFetchCertDetailFailed(error: Error) {
        view?.showErrorToast(message: error.localizedDescription)
    }
    
  • 第三步:Interactor层处理纯业务逻辑,比如网络请求、数据库读写,处理完成后通过代理/闭包回调结果给Presenter
    示例代码:
    func fetchCertDetail(certId: String) {
        // 执行网络请求
        NetworkService.request(.certDetail(id: certId)) { [weak self] result in
            switch result {
            case .success(let detail):
                self?.presenter?.didFetchCertDetailSuccess(detail: detail)
            case .failure(let error):
                self?.presenter?.didFetchCertDetailFailed(error: error)
            }
        }
    }
    
  • 第四步:Router层负责生成目标ViewController,完成参数注入,执行push/present操作
    示例代码:
    func pushToCertDetailPage(detail: CertDetail) {
        let detailVC = CertDetailViewController()
        // 给目标VC的Presenter注入参数
        detailVC.presenter = CertDetailPresenter(certDetail: detail)
        // 从当前导航控制器push
        currentNavigationController?.pushViewController(detailVC, animated: true)
    }
    

分层的核心目的是解耦和便于单元测试:

  • View层仅负责UI相关逻辑,不持有任何业务数据,完全依赖Presenter提供数据和指令
  • Interactor仅负责纯业务逻辑,和UI完全隔离,可以独立做单元测试
  • Router仅负责页面路由,所有跳转逻辑统一收口,修改页面跳转路径不需要修改业务层代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.08 08:12:03