Delegate未监听事件:iOS代理协议传Habit对象失败求助
问题排查与修复
代码里的几个致命错误
- 类声明语法错误:
NewHomeVC的定义缺少父类,正确写法是class NewHomeVC: UIViewController {,否则编译无法通过。 - 委托设置完全错位:
- 你在
NewCreateHabitVC的viewDidLoad里新建了一个NewHomeVC实例,这个实例和实际弹出它的NewHomeVC根本不是同一个对象,设置委托等于做无用功。 - 触发委托方法的时机错误:
didButtonTapped里先调用didEditHabit,但此时还没创建NewCreateHabitVC,newHomeVCDelegate是空的,方法根本不会执行。
- 你在
- 委托逻辑搞反:如果是要从
NewHomeVC传数据给刚弹出的NewCreateHabitVC,用委托是绕远路,直接给目标VC的属性赋值更简单;如果一定要用委托,得调整协议的归属和关联逻辑。
最直接的修复方案(直接传值)
这种方案最适合你当前的需求——弹出VC时直接传递数据:
class NewHomeVC: UIViewController { // 假设你这里有要传递的Habit实例 var habit: Habit! override func viewDidLoad() { super.viewDidLoad() } func didButtonTapped() { let vc = NewCreateHabitVC() // 直接把Habit传给目标VC vc.receivedHabit = self.habit vc.modalPresentationStyle = .popover self.present(vc, animated: true) } } class NewCreateHabitVC: UIViewController { // 定义接收Habit的属性 var receivedHabit: Habit! override func viewDidLoad() { super.viewDidLoad() setViews() setDelegates() addGestureRecognizer() // 拿到数据后更新UI updateUI(habit: receivedHabit) } func updateUI(habit: Habit) { // 你的UI更新逻辑 } }
如果一定要用委托(适合反向请求数据的场景)
如果你的场景是NewCreateHabitVC需要主动向NewHomeVC请求数据,那委托才是合理的,代码调整如下:
// 协议要继承AnyObject,这样委托对象可以用weak修饰避免循环引用 protocol HabitProviderDelegate: AnyObject { func getCurrentHabit() -> Habit } class NewHomeVC: UIViewController, HabitProviderDelegate { var habit: Habit! override func viewDidLoad() { super.viewDidLoad() } func didButtonTapped() { let vc = NewCreateHabitVC() // 把当前VC设为目标VC的委托 vc.habitDelegate = self vc.modalPresentationStyle = .popover self.present(vc, animated: true) } // 实现协议方法,提供Habit数据 func getCurrentHabit() -> Habit { return self.habit } } class NewCreateHabitVC: UIViewController { // 用weak修饰委托对象,防止循环引用 weak var habitDelegate: HabitProviderDelegate? override func viewDidLoad() { super.viewDidLoad() setViews() setDelegates() addGestureRecognizer() // 向委托请求数据并更新UI if let habit = habitDelegate?.getCurrentHabit() { updateUI(habit: habit) } } func updateUI(habit: Habit) { // 你的UI更新逻辑 } }
关键提醒
- 委托对象必须用
weak修饰,同时协议要继承AnyObject,否则会导致循环引用内存泄漏。 - 永远不要在子VC里新建父VC的实例来设置委托,必须关联实际弹出它的那个父VC对象。
- 正向传值(父给子)优先用属性赋值,委托更多用于反向回调(子给父发通知或请求数据)。
内容的提问来源于stack exchange,提问作者Evrim Demir
相关产品推荐
相关产品推荐

