0

This should be absolutely trivial but I can't find anything so:

I have a simple storyboard with navigation controller where I push a view controller, let's call it "Jane", from a view controller called "Bob".

So Bob wants to do something whenever Jane is dismissed after tapping the "back" button, like so:

- (IBAction) janeWasDismissed:(UIViewController *)jane
{
   // bob wants to ask what Jane did.
}

It's the simplest thing right? But I can't figure it out, surely Unwind Segues are not the right way? There must be a simple click & drag operation for this in Interface Builder, or a method on UIViewController which is called when the pushed view controller has popped?

thanks!

spinalwrap
  • 683
  • 1
  • 4
  • 17

2 Answers2

0

Actually it's not at all trivial. If Bob is going to need information from Jane, you need to arrange for Jane to send that information back to Bob. For example, in Jane's viewWillDisappear:, she can get herself a reference to Bob (by way of the navigation controller that they both share) and call some method in Bob.

You might object (quite reasonably) that this implies a knowledge of Bob's class on the part of Jane. The usual solution to that is even more non-trivial: it is that Bob, as he summons Jane, makes himself available to Jane as a delegate cast as a protocol that Jane defines. Thus Jane needs to know only one method of Bob - not his actual class, but the method that she herself has specified in her protocol.

matt
  • 515,959
  • 87
  • 875
  • 1,141
  • hm, interesting! I'm kind of thinking it should really be the other way around: As Bob invokes Jane, Bob knows Jane already. Why should Jane have a reference to Bob? – spinalwrap Mar 14 '16 at 15:20
  • The usual architecture is that Bob, as he summons Jane, makes himself available to Jane as a delegate cast as a protocol that Jane defines. Thus Jane needs to know only one method of Bob - not his actual class, but the method that she herself has specified in her protocol. – matt Mar 14 '16 at 15:21
  • ok thanks - will do that if it's the thing one does. Still seems odd, as modal controllers (alert controller etc.) do it the other way around. On the other hand, I see how this model makes sense if the pushed VC needs to pull data from the parent VC. – spinalwrap Mar 14 '16 at 15:26
  • No, modal controllers (presented view controllers) work the same way. This is the standard architecture for A creates B, B must hand info back to A as it goes out of existence. Even with a modern alert controller you are still handing B (the alert) a closure that refers back to A, and B must call it. – matt Mar 14 '16 at 15:40
  • hm true, it just looks different when handling it a closure block. Ok I'm still confused actually. If I want to send a message to Bob in `viewWillDisappear:`, I still need to handle a case where Jane will disappear other than navigating back to Bob... finicky: http://stackoverflow.com/questions/5217992/back-button-callback-in-navigationcontroller-in-ios – spinalwrap Mar 14 '16 at 15:44
  • Jane's `viewWillDisappear` calls `isBeingDismissed` or `isMovingFromParentViewController` to find out what's happening. – matt Mar 14 '16 at 16:05
  • Please see my book, and esp. my example here: https://github.com/mattneub/Programming-iOS-Book-Examples/tree/master/bk2ch06p264presentedViewController/ch19p601presentedViewController That's a presented view controller but the principle for pushed view controller is the same. – matt Mar 14 '16 at 16:06
0

There is no simple click & drag operation for this in Interface Builder.

There is no method on UIViewController which gets called when the pushed view controller has popped.

JaneViewController has to signal BobViewController.

class BobViewcontroller {
    var janeWasDismissed = false

    override func viewWillAppear(animated: Bool) {
        super.viewWillAppear(animated)
        if janesWasDismissed {
            // Do something
            janeWasDismissed = false
        }
    }

    override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
        if segue.identifier == "go-to-jane" {
            let destinationController = segue.destinationViewController as! JaneViewController
            destinationController.delegate = self
            self.janeWasDismissed = false
        }
    }
}

class JaneViewController {
    var delegate: BobViewcontroller?

    func dismissJane() {
        if let delegate = delegate {
            delegate.janeWasDismissed = true
            self.navigationController?.popViewControllerAnimated(false)
        }
    }
}
ryantxr
  • 4,119
  • 1
  • 11
  • 25