如何将UITableViewCell内嵌套UICollectionViewCell的数据传递到其他ViewController
报错原因及修复方案
核心错误点
- 数组越界隐患:
namearr仅包含5个元素,但collectionView数据源返回10个item,点击下标≥5的cell会直接崩溃 - 控件提前赋值失效:
DetailViewController刚实例化时,img等IBOutlet控件还未加载完成,直接给vc?.img.image赋值会无效甚至崩溃 - 导航控制器调用错误:
UITableViewCell没有navigationController属性,在cell内执行跳转逻辑本身就不符合规范,也会直接报错 - 可能的Storyboard实例化错误:需要确认
DetailViewController所在的Storyboard文件名是否确实为DetailViewController,默认项目中所有界面通常放在Main.storyboard中,名称填错会导致vc实例化失败
修复代码示例
1. 修正ExploreTableViewCell代码
添加回调闭包把点击事件和数据传递到上层ViewController,不要在cell内处理跳转
import UIKit class ExploreTableViewCell: UITableViewCell, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout{ @IBOutlet var collectionView: UICollectionView! // 定义回调闭包,把点击的图片名传递出去 var onItemClick: ((String) -> Void)? var namearr = ["images-1", "images-2", "images-3", "images-4", "images-5"] override func awakeFromNib() { super.awakeFromNib() collectionView.delegate = self collectionView.dataSource = self } override func setSelected(_ selected: Bool, animated: Bool) { super.setSelected(selected, animated: animated) } func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { // 修复数组越界,返回数组实际元素数量 return namearr.count } func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) // 这里给cell里的图片和标签赋值,按照你实际的控件tag或者自定义cell属性修改即可 if let imgView = cell.viewWithTag(100) as? UIImageView { imgView.image = UIImage(named: namearr[indexPath.row]) } if let label = cell.viewWithTag(101) as? UILabel { label.text = namearr[indexPath.row] } return cell } func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { return CGSize(width: 132, height: 134) } func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) { // 点击时触发回调,把图片名传出去 onItemClick?(namearr[indexPath.row]) } }
2. 修正DetailViewController代码
新增接收数据的存储属性,等界面加载完成后再给控件赋值
import UIKit class DetailViewController: UIViewController { @IBOutlet weak var img: UIImageView! @IBOutlet weak var nameLabel: UILabel! // 新增接收参数的属性,不要直接赋值IBOutlet var receiveImageName: String? override func viewDidLoad() { super.viewDidLoad() // 界面加载完成后再给控件赋值 if let imgName = receiveImageName { img.image = UIImage(named: imgName) nameLabel.text = imgName } } }
3. 在使用ExploreTableViewCell的宿主ViewController中处理跳转
在你显示这个TableView的VC的tableView(_:cellForRowAt:)方法里添加回调监听,执行跳转逻辑
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier: "ExploreTableViewCell", for: indexPath) as! ExploreTableViewCell // 监听cell的点击回调 cell.onItemClick = { [weak self] imageName in guard let self = self else { return } // 实例化DetailViewController,注意Storyboard名称要和你实际的一致 guard let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewController(withIdentifier: "DetailViewController") as? DetailViewController else { return } // 传递参数 vc.receiveImageName = imageName // 跳转 self.navigationController?.pushViewController(vc, animated: true) } return cell }
内容的提问来源于stack exchange,提问作者JESTIN SAJI
相关产品推荐
相关产品推荐

