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

如何在被present的ViewController dismiss后调用MainViewController指定方法?

我来给你几个靠谱的解决方案,完美适配你这个场景:

方案1:使用闭包(Completion Handler)推荐

这是最直接可控的方式,完全不会出现viewWillAppear/viewDidAppear那种多次触发的问题,逻辑也清晰。

首先在被present的ViewController里定义一个闭包属性:

class PresentedViewController: UIViewController {
    // 定义闭包,用来通知主VC执行后续操作
    var onDismissCompletion: (() -> Void)?

    // 用户触发操作的方法(比如按钮点击)
    @IBAction func userActionTapped(_ sender: UIButton) {
        // 先dismiss当前VC,在完成回调里触发闭包
        dismiss(animated: true) { [weak self] in
            self?.onDismissCompletion?()
        }
    }
}

然后在MainViewController里present这个VC时,绑定闭包到你要执行的方法:

class MainViewController: UIViewController {
    func presentMyViewController() {
        let presentedVC = PresentedViewController()
        // 绑定闭包,指定要执行的目标方法
        presentedVC.onDismissCompletion = { [weak self] in
            self?.presentNewViewController()
        }
        present(presentedVC, animated: true)
    }

    // 你需要执行的目标方法
    func presentNewViewController() {
        let newVC = UIViewController()
        newVC.view.backgroundColor = .blue
        present(newVC, animated: true)
    }
}

注意用[weak self]避免循环引用,闭包只会在dismiss完全完成后执行一次,精准符合你的需求。

方案2:使用代理模式(Delegate Pattern)

如果你的业务逻辑比较复杂,或者这个PresentedViewController需要和多个VC交互,代理模式会让代码结构更规范清晰。

首先定义代理协议:

protocol PresentedViewControllerDelegate: AnyObject {
    func presentedViewControllerDidFinish(_ vc: PresentedViewController)
}

然后在PresentedViewController里添加代理属性:

class PresentedViewController: UIViewController {
    // 用weak避免循环引用
    weak var delegate: PresentedViewControllerDelegate?

    @IBAction func userActionTapped(_ sender: UIButton) {
        dismiss(animated: true) { [weak self] in
            guard let self = self else { return }
            self.delegate?.presentedViewControllerDidFinish(self)
        }
    }
}

接下来让MainViewController遵守这个代理协议:

class MainViewController: UIViewController, PresentedViewControllerDelegate {
    func presentMyViewController() {
        let presentedVC = PresentedViewController()
        presentedVC.delegate = self
        present(presentedVC, animated: true)
    }

    // 实现代理方法,触发目标操作
    func presentedViewControllerDidFinish(_ vc: PresentedViewController) {
        presentNewViewController()
    }

    func presentNewViewController() {
        let newVC = UIViewController()
        newVC.view.backgroundColor = .blue
        present(newVC, animated: true)
    }
}

代理模式的好处是耦合度低,逻辑分工明确,适合中大型项目的场景。

方案3:通知机制(Notification)如果一定要用的话

你担心MainViewController接收不到通知?其实只要正确注册和移除通知,完全没问题——毕竟是MainVC present的这个VC,dismiss的时候MainVC肯定还在内存中,能正常收到通知。

首先定义一个专属的通知名称:

extension Notification.Name {
    static let presentedVCDismissed = Notification.Name("presentedVCDismissed")
}

在MainViewController里注册通知,记得在销毁时移除:

class MainViewController: UIViewController {
    override func viewDidLoad() {
        super.viewDidLoad()
        // 注册通知,绑定到目标方法
        NotificationCenter.default.addObserver(self, selector: #selector(presentNewViewController), name: .presentedVCDismissed, object: nil)
    }

    deinit {
        // 移除通知,避免野指针问题
        NotificationCenter.default.removeObserver(self)
    }

    func presentMyViewController() {
        let presentedVC = PresentedViewController()
        present(presentedVC, animated: true)
    }

    @objc func presentNewViewController() {
        let newVC = UIViewController()
        newVC.view.backgroundColor = .blue
        present(newVC, animated: true)
    }
}

最后在PresentedViewController里dismiss完成后发送通知:

class PresentedViewController: UIViewController {
    @IBAction func userActionTapped(_ sender: UIButton) {
        dismiss(animated: true) {
            // 发送通知
            NotificationCenter.default.post(name: .presentedVCDismissed, object: nil)
        }
    }
}

不过这个方案的缺点是耦合度高,通知是全局的,如果多个地方注册同名通知容易出问题,所以优先推荐前两种方案。

内容的提问来源于stack exchange,提问作者user3239711

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.26 08:53:53