How to pass data from modal view controller back when dismissed

If using a navigation controller you will have to first grab the UINavigation Controller and then get the correct ViewController from the Navigation Controller stack.

Here's how my code looked in that case.

@IBAction func dismissViewController(_ sender: UIBarButtonItem) {
    if let navController = presentingViewController as? UINavigationController {
       let presenter = navController.topViewController as! OOTDListViewController
        presenter.testValue = "Test"
    }
    dismiss(animated: true, completion: nil)
}

Depending on the data you want to pass, you can create a property in the presenting view controller, which you can set when dismissing the modal view controller, so you can spare yourself the delegate.

For example, you have a ContactsViewController, holding a var contacts: [Contact] = [] property. When you want to create a new contact, you present a modal view controller with the different values you need to create a new Contact object. When you are done and want to dismiss the view controller, you call the function as you did in your code, but set the property in the ContactsViewController. It will look something like this:

@IBAction func dismissViewController(_ sender: UIBarButtonItem) {
    if let presenter = presentingViewController as? ContactsViewController {
        presenter.contacts.append(newContact)
    }
    dismiss(animated: true, completion: nil)
}

If you don't want to use a delegate, this is how you go about it:

In your OOTDListViewController :

var testValue: String = ""

@IBAction func printReceivedValue(_ sender: UIButton) {
    print(testValue)
}

In your modal view controller (I'll call it PresentedViewController) :

@IBAction func dismissViewController(_ sender: UIBarButtonItem) {
    // if your OOTDListViewController is part of a UINavigationController stack, this check will probably fail. 
    // you need to put a breakpoint here and check if the presentingViewController is actually a UINavigationController.
    // in that case, you will need to access the viewControllers variable and find your OOTDListViewController
    if let presenter = presentingViewController as? OOTDListViewController {
        presenter.testValue = "Test"
    }
    dismiss(animated: true, completion: nil)
}

If you want to use a delegate, this is how to do it:

In your OOTDListViewController:

protocol ModalDelegate {
    func changeValue(value: String)
}
    
class OOTDListViewController: ModalDelegate {

    var testValue: String = ""
    @IBAction func presentViewController() {
        // here, you either create a new instance of the ViewController by initializing it, or you instantiate it using a storyboard. 
        // for simplicity, I'll use the first way
        // in any case, you cannot use a storyboard segue directly, bevause you need access to the reference of the presentedViewController object
        let presentedVC = PresentedViewController() 
        presentedVC.delegate = self
        present(presentedVC, animated: true, completion: nil)
    }

    func changeValue(value: String) {
         testValue = value
         print(testValue)
    }
}

In your PresentedViewController:

class PresentedViewController {
    var delegate: ModalDelegate? 
    var testValue: String = ""

    @IBAction func dismissViewController(_ sender: UIBarButtonItem) {
       if let delegate = self.delegate {
            delegate.changeValue(testValue)
        }
        dismiss(animated: true, completion: nil)
    }

}

Tags:

Ios

Swift