Swift代理问题:自定义Header返回按钮无法触发ViewController返回
嘿,我来帮你排查下这个问题!你说协议方法onBackButtonTap()已经被触发,但dismiss函数没执行,大概率是这几个常见的坑没踩对,咱们一步步来:
1. 先确认Delegate有没有正确赋值
这是协议传值最容易踩的坑!你得确保在ViewController里,给StoresFilterHeaderView的delegate属性明确设置成self。比如在配置Header的地方(比如UITableView的viewForHeaderInSection方法里):
func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "StoresFilterHeaderView") as! StoresFilterHeaderView header.delegate = self // 这行绝对不能忘! return header }
你说按钮动作已被接收,那这步可能没问题,但还是要再检查:有没有不小心把delegate设成了nil?或者因为没给delegate加weak修饰导致循环引用,让ViewController提前被释放了?
2. 检查dismiss的调用逻辑是否匹配VC的呈现方式
协议方法里的返回代码是不是用错了?比如:
func onBackButtonTap() { print("Back button tapped!") // 先加个打印,确认这个方法真的被触发了 // 这里要根据VC的呈现方式选对应的返回方法: // 如果当前VC是被present出来的: dismiss(animated: true, completion: nil) // 如果当前VC是被push到导航栈的: // navigationController?.popViewController(animated: true) }
要是你用了dismiss但VC其实是push进来的,那肯定没反应!这是很多人会搞混的点,一定要对应上。另外,如果VC被包在UINavigationController里present,那你需要dismiss的是导航控制器,而不是当前VC:navigationController?.dismiss(animated: true, completion: nil)
3. 确认Delegate的弱引用设置是否正确
协议定义要加class限制,并且delegate属性必须设为weak,避免循环引用导致ViewController内存异常:
// 协议要加class限制,才能用weak修饰delegate protocol StoresFilterHeaderViewDelegate: class { func onBackButtonTap() } class StoresFilterHeaderView: UICollectionReusableView { // delegate必须是weak,防止循环引用 weak var delegate: StoresFilterHeaderViewDelegate? @IBAction func backButtonTapped(_ sender: UIButton) { delegate?.onBackButtonTap() } }
要是没加weak,可能会导致VC无法正常释放,就算协议方法被调用,dismiss也可能因为上下文问题失效。
4. 最后再检查按钮的IBAction关联
你说按钮动作已被接收,这步大概率没问题,但还是可以再确认下:按钮的Touch Up Inside事件是不是正确关联到了Header里的backButtonTapped方法,有没有关联错对象或者重复关联?
给你贴个完整的正确示例参考:
Header类代码
import UIKit protocol StoresFilterHeaderViewDelegate: class { func onBackButtonTap() } class StoresFilterHeaderView: UICollectionReusableView { weak var delegate: StoresFilterHeaderViewDelegate? @IBAction func backButtonPressed(_ sender: UIButton) { delegate?.onBackButtonTap() } }
ViewController类代码
import UIKit class StoresFilterViewController: UIViewController, StoresFilterHeaderViewDelegate { @IBOutlet weak var tableView: UITableView! override func viewDidLoad() { super.viewDidLoad() // 注册Header(如果是用xib创建的) tableView.register(UINib(nibName: "StoresFilterHeaderView", bundle: nil), forHeaderFooterViewReuseIdentifier: "StoresFilterHeaderView") } } // MARK: - UITableViewDelegate extension StoresFilterViewController { func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { guard let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "StoresFilterHeaderView") as? StoresFilterHeaderView else { return nil } header.delegate = self return header } func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { return 60 // 根据你的Header高度调整 } } // MARK: - StoresFilterHeaderViewDelegate extension StoresFilterViewController { func onBackButtonTap() { print("Delegate method triggered!") // 根据实际呈现方式选择返回方法 dismiss(animated: true, completion: nil) // 要是是push进来的就用下面这句: // navigationController?.popViewController(animated: true) } }
你可以先加个打印确认协议方法确实被调用,然后根据VC的呈现方式调整返回代码,应该就能解决问题啦!
内容的提问来源于stack exchange,提问作者Victor Rius

