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

如何从作为FirstViewController容器视图的SecondViewController访问前者?

嘿,这个场景在iOS开发里太常见啦!当SecondViewController作为FirstViewController的容器视图时,反向访问的需求确实很普遍,我给你分享几种实用的实现方案,你可以根据自己的业务场景来选:

方案1:代理模式(最推荐,符合iOS设计规范)

这是Apple官方最提倡的组件通信方式,耦合度低,逻辑清晰,还能避免内存泄漏。步骤很简单:

  • 首先在SecondViewController里定义一个协议,声明你需要从Second调用First的方法:
protocol SecondVCDelegate: AnyObject {
    func secondVCDidTriggerAction(_ secondVC: SecondViewController, data: String?)
}
  • 然后在SecondViewController里添加一个弱引用的代理属性(必须加weak,防止循环引用):
class SecondViewController: UIViewController {
    weak var delegate: SecondVCDelegate?
    
    // 比如某个按钮点击时触发代理方法
    @IBAction func notifyFirstVCAction(_ sender: UIButton) {
        delegate?.secondVCDidTriggerAction(self, data: "来自SecondVC的消息")
    }
}
  • 接下来回到FirstViewController,遵守这个协议并实现方法,同时在获取到SecondViewController实例时把自己设为代理:
class FirstViewController: UIViewController, SecondVCDelegate {
    var secondVC: SecondViewController?
    
    // 假设你是通过prepare(for:sender:)获取容器视图的VC
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if let vc = segue.destination as? SecondViewController {
            secondVC = vc
            vc.delegate = self // 设置代理
        }
    }
    
    // 实现代理方法
    func secondVCDidTriggerAction(_ secondVC: SecondViewController, data: String?) {
        print("收到SecondVC的消息:\(data ?? "")")
        // 这里处理FirstVC的逻辑,比如更新UI、调用方法等
    }
}
方案2:闭包(Block)回调

如果觉得代理的代码有点繁琐,闭包也是个不错的选择,写法更简洁:

  • 在SecondViewController里定义一个可选的闭包属性:
class SecondViewController: UIViewController {
    var onActionTriggered: ((String?) -> Void)?
    
    @IBAction func notifyFirstVCAction(_ sender: UIButton) {
        onActionTriggered?("来自SecondVC的闭包消息")
    }
}
  • 在FirstViewController里给闭包赋值,注意用[weak self]避免循环引用:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let vc = segue.destination as? SecondViewController {
        secondVC = vc
        vc.onActionTriggered = { [weak self] message in
            guard let self = self else { return }
            print("收到闭包消息:\(message ?? "")")
            // 处理FirstVC的逻辑
        }
    }
}
方案3:弱引用直接持有父VC

这种方式最直接,但要特别注意内存管理:

  • 在SecondViewController里添加一个弱引用的FirstViewController属性:
class SecondViewController: UIViewController {
    weak var parentFirstVC: FirstViewController?
    
    @IBAction func callFirstVCMethod(_ sender: UIButton) {
        parentFirstVC?.doSomething() // 直接调用FirstVC的方法
    }
}
  • 在FirstViewController里获取到SecondViewController后赋值:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let vc = segue.destination as? SecondViewController {
        secondVC = vc
        vc.parentFirstVC = self
    }
}

注意:一定要用weak修饰这个属性!否则FirstVC和SecondVC会互相持有,导致内存泄漏。

方案4:通知中心(NSNotificationCenter)

这种方式耦合度最低,但不够直观,适合跨多层级的通信,一般不推荐用在这种明确的容器父子场景:

  • 在FirstViewController里注册通知:
override func viewDidLoad() {
    super.viewDidLoad()
    NotificationCenter.default.addObserver(self, selector: #selector(handleSecondVCNotification(_:)), name: NSNotification.Name("SecondVCActionNotification"), object: nil)
}

@objc func handleSecondVCNotification(_ notification: Notification) {
    if let data = notification.userInfo?["data"] as? String {
        print("收到通知消息:\(data)")
        // 处理逻辑
    }
}

// 记得在deinit里移除观察者
deinit {
    NotificationCenter.default.removeObserver(self)
}
  • 在SecondViewController里发送通知:
@IBAction func sendNotification(_ sender: UIButton) {
    NotificationCenter.default.post(name: NSNotification.Name("SecondVCActionNotification"), object: nil, userInfo: ["data": "来自SecondVC的通知消息"])
}

总结一下:如果是简单的通信,闭包或者弱引用属性都可以;如果是比较复杂的交互,推荐用代理模式,扩展性更好;通知中心尽量少用在这种父子容器的场景,避免代码逻辑分散不好维护。

内容的提问来源于stack exchange,提问作者Dmytrii G.

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.20 08:13:02