如何通过Segue从UITableViewController传递数组到ViewController
你的代码传值失败核心是执行顺序问题:你在didSelectRowAt方法中先调用了tableView.deselectRow(at: indexPath, animated: true),这行代码会在跳转触发前就清除行的选中状态,等执行到prepare(for:sender:)方法时,self.tableView.indexPathForSelectedRow读取到的是nil,不会进入传值逻辑分支,目标控制器自然拿不到数组数据。
另外存在一个潜在兼容问题:如果你的Segue终点是被UINavigationController包裹的ViewController,直接把segue.destination强转成ViewController会失败,也会导致传值失效。
推荐用稳定性最高的方案1,不需要依赖Cell选中态:
方案1:通过sender直接传递选中的IndexPath
修改MyTableViewController的选中和传值逻辑:override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) // 直接把当前选中的indexPath作为sender传入 performSegue(withIdentifier: "showDetail", sender: indexPath) } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard segue.identifier == "showDetail", // 从sender中直接取出indexPath,不再依赖tableView的选中状态 let indexPath = sender as? IndexPath else { return } // 兼容两种Segue情况:直接连到ViewController、连到包裹ViewController的导航控制器 let targetVC: ViewController? if let nav = segue.destination as? UINavigationController { targetVC = nav.topViewController as? ViewController } else { targetVC = segue.destination as? ViewController } // 传值 targetVC?.getDescriptions = faculties[indexPath.row].descriptions }改完之后目标页面的
viewDidLoad中print(getDescriptions)就能正常打印出对应的数据,tableView也会自动加载对应行数的内容。方案2:调整代码执行顺序(改动最小,稳定性稍弱)
如果不想修改传参逻辑,只需要把取消选中的代码挪到performSegue调用之后即可,保证执行prepare方法时行还处于选中状态:override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { let cell = tableView.cellForRow(at: indexPath) // 先触发跳转传值 performSegue(withIdentifier: "showDetail", sender: cell) // 传值完成后再取消选中 tableView.deselectRow(at: indexPath, animated: true) }注意如果用这个方案,还是要补上上面提到的导航控制器类型判断逻辑,否则当Segue连到导航控制器时依然会传值失败。
改完之后如果还是不显示数据,可以检查两点:
- 目标页面的tableView的
delegate、dataSource连线是否正常,Cell复用IDdetailIdentifier是否和Storyboard里配置的一致 - 如果传值时机晚于
viewDidLoad(比如用其他跳转方式),需要在给getDescriptions赋值后调用tableView.reloadData()刷新列表,当前代码用Segue的生命周期是先传值再走viewDidLoad,不需要额外调用刷新。
内容的提问来源于stack exchange,提问作者Codingman11

