10

A user is in a view controller which calls a modal. When self.dismissViewController is called on the modal, a function needs to be run on the initial view controller. This function also requires a variable passed from the modal.

This modal can be displayed from a number of view controllers, so the function cannot be directly called in a viewDidDisappear on the modal view.

How can this be accomplished in swift?

Michael Voccola
  • 1,827
  • 6
  • 20
  • 46
  • What's the problem? Is it that you don't know how to talk from one view controller to another? – matt Dec 15 '14 at 03:36
  • I need to perform a function from the VC that displayed the modal initially. If this was a segue, I could likely do this via prepareForSegue with conditionals based on the segue identifier, but that doesn't seem to be working when using dismissViewController from a modal. – Michael Voccola Dec 15 '14 at 03:39
  • 1
    You likely want to do this using an unwind segue on the modal, that way you can set up a function on the parent that gets called when it unwinds. http://stackoverflow.com/questions/12561735/what-are-unwind-segues-for-and-how-do-you-use-them – porglezomp Dec 15 '14 at 03:41
  • The usual pattern is that the modal declares a delegate and whoever presents the modal declares himself the delegate. Now you have a communication path back. – matt Dec 15 '14 at 03:41
  • Actually if you do what @porglezomp said you _do_ get a prepareForSegue from the modal back to wherever. – matt Dec 15 '14 at 03:42
  • 1
    For a downloadable example of the usual pattern, see this code from my book: https://github.com/mattneub/Programming-iOS-Book-Examples/tree/master/bk2ch06p264presentedViewController/ch19p601presentedViewController Notice how ViewController makes himself SecondViewController's delegate before presenting it. Then SecondViewController has a callback to the delegate on dismissal. – matt Dec 15 '14 at 03:45

3 Answers3

7

How about delegate?

Or you can make a ViewController like this:

typealias Action = (x: AnyObject) -> () // replace AnyObject to what you need
class ViewController: UIViewController {
  func modalAction() -> Action {
    return { [unowned self] x in 
      // the x is what you want to passed by the modal viewcontroller
      // now you got it
    }
  }
}

And in modal:

class ModalViewController: UIViewController {
  var callbackAction: Action?
   override func viewDidDisappear(_ animated: Bool) {
    let x = … // the x is what you pass to ViewController
    callbackAction?(x)
  }
}

Of course, when you show ModalViewController need to set callbackAction like this modal.callbackAction = modalAction() in ViewController

Emil
  • 205
  • 2
  • 7
Pikaurd
  • 1,114
  • 1
  • 8
  • 22
6

The answer supplied and chosen by the question asker (Michael Voccola) didn't work for me, so I wanted to supply another answer option. His answer didn't work for me because viewDidAppear does not appear to run when I dismiss the modal view.

I have a table and a modal VC that appears and takes some table input. I had no trouble sending the initial VC the modal's new variable info. However, I was having trouble getting the table to automatically run a tableView.reloadData function upon dismissing the modal view.

The answer that worked for me was in the comments above:

You likely want to do this using an unwind segue on the modal, that way you can set up a function on the parent that gets called when it unwinds. stackoverflow.com/questions/12561735/… – porglezomp Dec 15 '14 at 3:41

And if you're only unwinding one step (VC2 to VC1), you only need a snippet of the given answer:

Step 1: Insert method in VC1 code

When you perform an unwind segue, you need to specify an action, which is an action method of the view controller you want to unwind to:

@IBAction func unwindToThisViewController(segue: UIStoryboardSegue) {
    //Insert function to be run upon dismiss of VC2
}

Step 2: In storyboard, in the presented VC2, drag from the button to the exit icon and select "unwindToThisViewController"

After the action method has been added, you can define the unwind segue in the storyboard by control-dragging to the Exit icon.

And that's it. Those two steps worked for me. Now when my modal view is dismissed, my table updates. Just figured I'd add this, in case anyone else's issue wasn't solved by the chosen answer.

Dave G
  • 12,042
  • 7
  • 57
  • 83
4

I was able to achieve the desired result by setting a Global Variable as a boolean value from the modal view controller. The variable is initiated and made available from a struct in a separate class.

When the modal is dismissed, the viewDidAppear method on the initial view controller responds accordingly to the value of the global variable and, if needed, flips the value on the global variable.

I am not sure if this is the most efficient way from a performance perspective, but it works perfectly in my scenario.

Michael Voccola
  • 1,827
  • 6
  • 20
  • 46