如何将ChildVC的计数器数据回传至MainVC对应的CollectionView Cell
嘿,这个需求在iOS开发里挺常见的,咱们用代理模式或者闭包回调都能轻松实现,我给你拆解两种方案,你挑顺手的来就行~
方案一:代理模式(传统iOS回调方式)
这种方式很规范,适合稍微复杂一点的交互场景,步骤如下:
- 先在
ChildVC里定义代理协议,声明数据回传的方法
// ChildVC.swift protocol ChildVCDelegate: AnyObject { // 参数包含选中数量和对应Cell的索引,方便MainVC定位更新 func didUpdateSelectedCount(_ count: Int, forCellIndex index: Int) } class ChildVC: UIViewController { // 代理属性必须用weak,避免循环引用 weak var delegate: ChildVCDelegate? // 记录当前是从哪个Cell跳过来的 var currentCellIndex: Int = 0 // 你的计数器变量,监听变化更新界面 var selectedCount: Int = 0 { didSet { countLabel.text = "\(selectedCount) selected" } } // 假设用户点击确认按钮完成选择,触发回传 @IBAction func confirmBtnTapped(_ sender: UIButton) { // 通过代理把数据传给MainVC delegate?.didUpdateSelectedCount(selectedCount, forCellIndex: currentCellIndex) // 关闭ChildVC(如果是push进来的就用popViewController) dismiss(animated: true) } }
- 在
MainVC里遵守代理协议,实现回传逻辑并更新Cell
// MainVC.swift class MainVC: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate, ChildVCDelegate { // 存储每个Cell的选中数量,初始全为0 private var cellSelectedCounts: [Int] = Array(repeating: 0, count: 5) // 跳转Segue前,给ChildVC传索引并设置代理 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard segue.identifier == "ToChildVC", // 记得给Segue设置这个唯一标识 let childVC = segue.destination as? ChildVC, let selectedCell = sender as? UICollectionViewCell, let indexPath = collectionView.indexPath(for: selectedCell) else { return } // 把当前Cell的索引传给ChildVC childVC.currentCellIndex = indexPath.item // 设置代理 childVC.delegate = self // 把当前Cell已有的计数传给ChildVC,进去就能显示之前的选择 childVC.selectedCount = cellSelectedCounts[indexPath.item] } // 实现代理方法,更新对应Cell的计数并刷新界面 func didUpdateSelectedCount(_ count: Int, forCellIndex index: Int) { cellSelectedCounts[index] = count // 只刷新对应的Cell,比全量刷新更高效 collectionView.reloadItems(at: [IndexPath(item: index, section: 0)]) } // CollectionView数据源方法,给Cell设置标签文本 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YourCellID", for: indexPath) as! YourCustomCell cell.countLabel.text = "\(cellSelectedCounts[indexPath.item]) selected" return cell } }
方案二:闭包回调(更简洁的方式)
如果你的交互逻辑比较简单,闭包写法会更清爽,不用额外写协议:
- 在
ChildVC里定义回调闭包
// ChildVC.swift class ChildVC: UIViewController { var currentCellIndex: Int = 0 var selectedCount: Int = 0 { didSet { countLabel.text = "\(selectedCount) selected" } } // 定义回调闭包,@escaping表示闭包会在VC生命周期外执行 var updateCountCallback: ((Int, Int) -> Void)? @IBAction func confirmBtnTapped(_ sender: UIButton) { // 执行闭包回传数据 updateCountCallback?(selectedCount, currentCellIndex) dismiss(animated: true) } }
- 在
MainVC的Segue准备阶段设置闭包
// MainVC.swift class MainVC: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate { private var cellSelectedCounts: [Int] = Array(repeating: 0, count: 5) override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard segue.identifier == "ToChildVC", let childVC = segue.destination as? ChildVC, let selectedCell = sender as? UICollectionViewCell, let indexPath = collectionView.indexPath(for: selectedCell) else { return } childVC.currentCellIndex = indexPath.item childVC.selectedCount = cellSelectedCounts[indexPath.item] // 设置闭包,用[weak self]避免循环引用 childVC.updateCountCallback = { [weak self] count, index in guard let self = self else { return } self.cellSelectedCounts[index] = count self.collectionView.reloadItems(at: [IndexPath(item: index, section: 0)]) } } // 同样的Cell数据源方法,设置标签文本 func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "YourCellID", for: indexPath) as! YourCustomCell cell.countLabel.text = "\(cellSelectedCounts[indexPath.item]) selected" return cell } }
注意事项
- 一定要给Storyboard里的Segue设置唯一的
identifier(比如示例里的ToChildVC),不然prepare(for:sender:)里识别不了跳转 - 如果
ChildVC是通过push方式跳转的,关闭时要换成navigationController?.popViewController(animated: true) - 闭包里记得用
[weak self],防止循环引用导致内存泄漏
内容的提问来源于stack exchange,提问作者Joe
相关产品推荐
相关产品推荐

