从被呈现的视图控制器中访问呈现的视图控制器?

6
我有一个视图控制器(包含我的菜单)显示在另一个视图控制器(我的应用程序)之上。
我需要从被呈现的视图控制器(我的菜单)访问呈现的视图控制器(我的应用程序),例如访问一些变量或使呈现的视图控制器执行其中的一个segue。
但是,我无法弄清楚如何做到这一点。我知道“presentingViewController”和“presentedViewController”变量,但我没有成功地使用它们。
有什么想法吗?
代码(来自被呈现的VC,其中引用了AppDelegate,其中引用了窗口):
if let presentingViewController = self.appDelegate.window?.rootViewController?.presentingViewController {
    presentingViewController.performSegue(withIdentifier: "nameOfMySegue", sender: self)
}

2
解决这个问题的常用模式是使用委托设计模式。在您的菜单VC中声明一个委托,并将第一个VC设置为委托。现在,您可以在委托上设置属性或调用方法。另一种方法可能是使用通知模式。 - TheAppMentor
1
@TheAppMentor提供了两种比直接引用呈现的视图控制器更好的设计模式。然而,如果您想要一个强耦合的关系,Apple确实提供了presentingViewController - dmorrow
这两种方法都可以实现。非常感谢。 - vbuzze
2个回答

12

这里使用委托设计模式与表示视图控制器进行交流。

首先声明一个协议,列出所有委托应该响应的变量和方法。

protocol SomeProtocol {

    var someVariable : String {get set}

    func doSomething()
}

下一步:使您的展示视图控制器符合协议。 将您的展示VC设置为代理

class MainVC: UIViewController, SomeProtocol {

    var someVariable: String = ""

    func doSomething() {
        // Implementation of do
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        // Your code goes here.

        if let destVC = segue.destination as? SubVC{
            destVC.delegate = self
        }
    }

}

最后,当你准备在呈现 VC 上调用方法(Delegate)时。

class SubVC: UIViewController {
    var delegate : SomeProtocol?


    func whenSomeEventHappens() {

        // For eg : When a menu item is selected

        // Set some Variable
        delegate?.someVariable = "Some Value"

        // Call a method on the deleate
        delegate?.doSomething()
    }

}

2
协议模式的解释非常简单易懂。干杯! - Marcos
1
我刚开始逐渐理解的一个主题的简明解释。将此页面加为书签以备将来参考。谢谢。 - Steve Hancocks

5
假设 VCApplication 正在呈现 VCMenu,在 VCMenu 中,你可以通过以下方式访问 VCApplication:
weak let vcApplication = self.presentingViewController as? VCApplicationType

您的示例self.appDelegate.window?.rootViewController?.presentingViewController正在查找呈现rootViewController的ViewController - 它将是nil

编辑根据TheAppMentor的建议,我已经添加了weak以避免保留循环。


1
虽然这种方法可以工作,但会导致强引用循环。这是因为,现在你的呈现VC引用菜单VC,而菜单VC反过来持有对你的呈现VC的引用。 - TheAppMentor
它奏效了!非常感谢。似乎在呈现的视图控制器未被解除之前,您无法在呈现的vc上执行segue。您必须先解除呈现的视图,然后调用segue。我最终得到: self.dismiss(animated: true, completion: nil) if let presentingVC = self.presentingViewController as? PresentingVCType { presentingVC.performSegue(withIdentifier: "nameOfMySegue", sender: self) } - vbuzze
这并不考虑UITabViewControllers和UINavigationControllers。 - ScottyBlades

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接