基于CellRepresentable协议,如何通过cellSelected实现TableViewCell跳转ViewController?
当然可行!这里是具体实现方案
你的思路没问题,不过因为struct是值类型,而且我们应该尽量让ViewModel和UI层(比如UINavigationController)解耦,所以不能直接在cellSelected()里直接做跳转操作。我们可以通过闭包回调的方式,把跳转的逻辑交给持有导航控制器的ViewController来处理,同时保留你现有的CellRepresentable协议结构。
步骤1:给ViewModel添加回调闭包
首先修改你的ProfileNameViewModel,添加一个可选闭包属性,用来传递点击事件的处理逻辑:
struct ProfileNameViewModel { // 添加这个闭包,用于接收点击后的跳转逻辑 var onCellSelected: (() -> Void)? }
步骤2:在cellSelected()里触发闭包
接着在CellRepresentable的扩展实现中,调用这个闭包:
extension ProfileNameViewModel: CellRepresentable { // ... 其他方法保持不变 ... func cellSelected() { // 触发回调,把点击事件传递给外部 onCellSelected?() } }
步骤3:在ViewController中绑定跳转逻辑
在你的TableViewController里,创建ViewModel的时候,给onCellSelected赋值,把跳转的UI逻辑写在这里:
// 假设你的数据源数组是这样的 var cellViewModels: [CellRepresentable] = [] // 在初始化数据源或者cellForRowAt方法中 func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let viewModel = ProfileNameViewModel() // 绑定跳转逻辑,注意用[weak self]避免循环引用 viewModel.onCellSelected = { [weak self] in guard let self = self else { return } // 创建你要跳转的目标ViewController let targetVC = YourTargetViewController() // 利用NavigationController完成跳转 self.navigationController?.pushViewController(targetVC, animated: true) } cellViewModels.append(viewModel) return viewModel.cellInstance(of: tableView, for: indexPath) }
步骤4:在TableView的点击方法中调用cellSelected()
最后,在ViewController的tableView(_:didSelectRowAt:)方法里,获取对应的ViewModel并调用cellSelected():
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let viewModel = cellViewModels[indexPath.row] viewModel.cellSelected() // 可选:点击后取消选中状态 tableView.deselectRow(at: indexPath, animated: true) }
为什么这样做?
- 保持了ViewModel的纯净性:它不需要知道任何UIKit的类(比如
UINavigationController),只负责传递事件,符合MVVM的架构原则。 - 利用了你现有的
CellRepresentable协议结构,不需要大幅修改原有代码。 - 闭包的方式灵活,每个ViewModel可以绑定不同的跳转逻辑,适配不同的场景。
内容的提问来源于stack exchange,提问作者decipher
相关产品推荐
相关产品推荐

