iOS委托模式问题:从TableView跳转传数据时Delegate属性为nil的求助
解决iOS委托模式中Delegate属性为nil的问题
嘿,我帮你揪出问题啦!你这是踩了委托模式里一个很常见的新手坑,咱们一步步拆解原因和解决办法:
问题根源
你代码里的delegate一直为nil,核心原因是你设置委托的对象根本不是正在和用户交互的那个ViewController:
- 在
SecondController的viewDidLoad里,你新创建了一个ViewController实例,并且给这个新实例设置了delegate,但这个新对象和你之前显示TableView的那个ViewController完全是两个独立的实例!原来的ViewController的delegate属性依然是空的,所以当你点击Cell调用delegate?.updateProperties时,自然没有任何反应。 - 另外,你试图通过IBOutlet的
didSet来更新UI,但这些控件在viewDidLoad之前还没完成初始化,而且你的s1、s2、img初始值都是空的,即使赋值成功,didSet也没法正确更新界面。
修正方案
正确的逻辑应该是:在跳转到SecondController之前,把当前ViewController的delegate绑定到即将弹出的SecondController实例上,同时调整UI更新的时机。
1. 修正ViewController的didSelectRowAt方法
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { tableView.deselectRow(at: indexPath, animated: true) let storyboard = UIStoryboard(name: Constants.storyboardName, bundle: nil) let nextController = storyboard.instantiateViewController( withIdentifier: Constants.destinationController ) as! SecondController // 关键:把当前ViewController的delegate设置为即将弹出的SecondController self.delegate = nextController let data = arr[indexPath.row] // 现在调用delegate方法就能触发SecondController的实现了 delegate?.updateProperties(data) present(nextController, animated: true, completion: nil) }
2. 修正SecondController的代码
删掉viewDidLoad里新建ViewController的无效代码,直接在委托方法里更新UI:
import UIKit class SecondController: UIViewController { @IBOutlet weak var picture: UIImageView! @IBOutlet weak var label11: UILabel! @IBOutlet weak var label22: UILabel! override func viewDidLoad() { super.viewDidLoad() view.backgroundColor = .systemRed // 移除这里新建ViewController的代码,完全不需要 } } extension SecondController: SendDataDelegate { func updateProperties(_ data: CellData) { // 直接在这里更新UI,此时IBOutlet已经完成初始化 label11.text = data.str1 label22.text = data.str2 picture.image = data.img } }
3. 额外优化(避免循环引用)
为了防止内存泄漏,建议给委托协议加上class限制,并把delegate声明为弱引用:
// 修改协议定义 protocol SendDataDelegate: class { func updateProperties(_ data: CellData) } // 在ViewController里修改delegate的声明 weak var delegate: SendDataDelegate?
为什么这样改?
当你点击Cell时,先实例化SecondController,把它设置为当前ViewController的delegate,然后调用委托方法传递数据。此时SecondController的视图控件已经完成初始化准备,直接赋值就能正确显示数据,不会出现之前的nil问题啦。
内容的提问来源于stack exchange,提问作者Abanoub Ashraf
相关产品推荐
相关产品推荐

