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
相关产品推荐
相关产品推荐

