You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Delegate未监听事件:iOS代理协议传Habit对象失败求助

问题排查与修复

代码里的几个致命错误

  1. 类声明语法错误:NewHomeVC的定义缺少父类,正确写法是class NewHomeVC: UIViewController {,否则编译无法通过。
  2. 委托设置完全错位:
    • 你在NewCreateHabitVC的viewDidLoad里新建了一个NewHomeVC实例,这个实例和实际弹出它的NewHomeVC根本不是同一个对象,设置委托等于做无用功。
    • 触发委托方法的时机错误:didButtonTapped里先调用didEditHabit,但此时还没创建NewCreateHabitVC,newHomeVCDelegate是空的,方法根本不会执行。
  3. 委托逻辑搞反:如果是要从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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.09 12:45:43