呈现ViewController 不工作

Posted

技术标签:

【中文标题】呈现ViewController 不工作【英文标题】:presentingViewController not working 【发布时间】:2018-07-11 16:00:42 【问题描述】:

当我关闭弹出 ViewController 时,我想在呈现的 ViewController 上调用一个方法。我像这样从“MainViewController”启动弹出窗口:(在 EzPopup 库的帮助下,但我认为这不重要)

@IBAction func onStartWorkout(_ sender: UIButton) 

    let startWorkoutVC = storyboard!.instantiateViewController(withIdentifier: "CardContent") as! StartWorkout_ViewController

    let popupVC = PopupViewController(contentController: startWorkoutVC, popupWidth: 300, popupHeight: 500)
    popupVC.cornerRadius = 10

    present(popupVC, animated: true)

然后当我关闭弹出窗口时,我会这样做:

func dissmissPopup()  
    if let presenter = presentingViewController as? MainViewController 
        presenter.startWorkout(index: 0, isSNR: true)
    
    self.dismiss(animated: true, completion: nil)

但不会调用该方法。 presentingViewController 是如何工作的,为什么我对 MainViewController 的引用不起作用?

【问题讨论】:

这个dissmissPopup方法在哪个类中? 因为 presentingViewController 为 nil @Popmedic presentingViewControllerUIViewController 的属性。 @rmaddy 如你所料,我在“StartWorkout_ViewController”上 @Sh_Khan 我知道它的 nil,问题是为什么它是 nil 以及如何解决这个问题? 【参考方案1】:

假设dissmissPopup 在你的StartWorkout_ViewController 类中,那么presentingViewController 将是nil,因为你没有呈现StartWorkout_ViewController,你正在呈现PopupViewControllerPopupViewControllerpresentingViewController 应该是您的 MainViewController

根据PopupViewController 的编写方式,您应该能够通过访问parent 获得所需的内容(给您PopupViewController,然后访问它的presentingViewController

func dissmissPopup()  
    if let presenter = parent?.presentingViewController as? MainViewController 
        presenter.startWorkout(index: 0, isSNR: true)
    

    self.dismiss(animated: true, completion: nil)

现在,说了这么多,不要这样做。这是一个糟糕而脆弱的设计。您正在对StartWorkout_ViewController 进行硬编码,知道MainViewController 需要调用一些特定的方法。

正确的解决方案是定义协议和委托。然后StartWorkout_ViewController 简单地调用它的委托上的协议方法(不关心它到底是谁)。而MainViewController 将自己设置为StartWorkout_ViewController 的委托并实现协议的方法。

这种方法使StartWorkout_ViewController 无需知道是谁呈现它或如何呈现它。它消除了StartWorkout_ViewController 知道专门调用名为startWorkout 的方法的需要。它还允许其他类呈现 MainViewController 并在它被解除时执行它需要的任何操作,而无需对 MainViewController 进行进一步的硬编码更改。

以下是使用协议和委托实现此功能的粗略大纲:

StartWorkout_ViewController.swift:

protocol StartWorkoutDelegate: class 
    func complete() // add any necessary parameters


class StartWorkout_ViewController: UIViewController 
    weak var delegate: StartWorkoutDelegate?

    func dissmissPopup()  
        delegate?.complete() // add any necessary parameters

        self.dismiss(animated: true, completion: nil)
    

MainViewController.swift:

class MainViewController: UIViewController, StartWorkoutDelegate 
    @IBAction func onStartWorkout(_ sender: UIButton) 
        let startWorkoutVC = storyboard!.instantiateViewController(withIdentifier: "CardContent") as! StartWorkout_ViewController
        startWorkoutVC.delegate = self

        let popupVC = PopupViewController(contentController: startWorkoutVC, popupWidth: 300, popupHeight: 500)
        popupVC.cornerRadius = 10

        present(popupVC, animated: true)
    

    func complete() 
        startWorkout() // add any necessary parameters
    

【讨论】:

感谢您的快速回答! 'parent?.presentingViewController' 的第一种方法不起作用。但我也宁愿采用第二种方式。您能否提供一个小代码示例?我是 swift 新手(来自 java),我知道协议是什么,但我不明白“从其委托调用协议方法”是什么意思。 非常感谢!我明白了。

以上是关于呈现ViewController 不工作的主要内容,如果未能解决你的问题,请参考以下文章

如何在不知道新的 VC 的情况下将 ViewController 呈现在另一个之上?

UIPickerView 的 ViewController 在选择后冻结

从上到下 Swift 呈现 ViewController

呈现的 ViewController 将被加载但不出现

如何将 ViewController 呈现为具有透明背景的弹出式 VC?

从 Swift 中的其他类更改 ViewController 的对象