9

Basically, I have a button in a slide-out menu (which is its own view controller that covers part of the Origin screen, let's call it Menu) that, when pressed, performs a modal segue to another controller, let's say Destination.

Is there any way that upon pressing the button in Menu (to go to Destination), that I can dismiss Menu back to Origin, and THEN segue to Destination?

It sounds silly but it's something that I think I've seen apps do before. In my case, the reason for wanting to do this is that once I press "Done" on Destination, it dismisses that controller back to Menu, when I want it to just dismiss back to Origin. I can't just perform a segue back to Origin from Destination.

Code:

This is how I open the Menu from Origin:

let interactor = Interactor()

@IBAction func openMenu(_ sender: AnyObject) {
    performSegue(withIdentifier: "openMenu", sender: nil)
}


@IBAction func edgePanGesture(sender: UIScreenEdgePanGestureRecognizer) {
    let translation = sender.translation(in: view)

    let progress = MenuHelper.calculateProgress(translationInView: translation, viewBounds: view.bounds, direction: .Right)

    MenuHelper.mapGestureStateToInteractor(
        gestureState: sender.state,
        progress: progress,
        interactor: interactor){
            self.performSegue(withIdentifier: "openMenu", sender: nil)
    }
}

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if let destinationViewController = segue.destination as? MenuViewController {
        destinationViewController.transitioningDelegate = self
        destinationViewController.interactor = interactor
        destinationViewController.currentRoomID = self.currentRoomID
    }
}

This is my prepareForSegue from Menu to Destination currently, nothing fancy:

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    super.prepare(for: segue, sender: sender)

    let inviteVC = segue.destination as! InviteVipViewController
    inviteVC.currentRoomID = self.currentRoomID
}

And finally to dismiss Destination is just a simple

@IBAction func cancelButtonPressed(_ sender: Any) {
    self.dismiss(animated: true, completion: nil)
}

I saw this question which is basically what I'm trying to do but there was no answer unfortunately: Performing segue after dismissing modal swift

Sorry if this sounds confusing, but if anyone knows what I'm talking about and can let me know how I can set up the segues/prepareForSegues to make it work, any input would be appreciated!

Community
  • 1
  • 1
KingTim
  • 1,281
  • 4
  • 21
  • 29
  • Since you're already using segues, why not do an unwind segue from Destination? Implement the didUnwind in Origin and it should skip Menu – GetSwifty Apr 20 '17 at 18:34
  • That seems like it could be what I need, I just tried it out but the only issue is that it stops on the menu momentarily before going back to the original controller. Is there any way to get around that? – KingTim Apr 20 '17 at 18:45

3 Answers3

17

Based on a modification to this answer, the following should work:

In your storyboard, remove the segue that is triggered by tapping your menu button and goes to Destination.

Create a new segue that goes from the Origin view controller to Destination view controller. This segue is going to be manually performed.

When your Destination option is selected in Menu, have Menu dismiss itself and then perform the Destination segue on Origin, like this:

    // This code goes in Menu, and you should call it when
    //    the menu button is tapped.
    //
    // presentingViewController is Origin
    weak var pvc = self.presentingViewController

    self.dismiss(animated: true) {

        // Menu has been dismissed, but before it is destroyed
        //  it calls performSegue on Origin
        pvc?.performSegue(withIdentifier: "openDestination", sender: nil)
    }

When Destination is dismissed, you should see Origin, without seeing Menu at all.

I tested this in a sample app where "Menu" was not a slide out, but a full modal view controller, and it worked for me.

EDIT: While troubleshooting with @KingTim, he found that we needed to wire the segue from the UINavigationController, not Origin, to the Destination. This is because Origin is inside a navigation controller. After that discovery, it worked.

Community
  • 1
  • 1
Mike Taverne
  • 9,156
  • 2
  • 42
  • 58
  • Thanks, that's interesting - I tried this, and when I dismissed Destination, it went back to Menu, not Origin. To be more specific, I added your code exactly (except my segue name is different) to my IBAction that handles the menu button being tapped to present Destination. – KingTim Apr 21 '17 at 15:00
  • Actually, I misread your comment. The code in your answer should be in the Origin controller? How do I call the Destination segue on Origin? I would generally call the segue in the IBAction of the menu button being pressed, which is obviously hooked up to the Menu controller. – KingTim Apr 21 '17 at 15:17
  • @KingTim I've updated my answer to address your questions. Please re-read the entire answer. The solution didn't change, but I added comments that I hope clarify things. Let me know. – Mike Taverne Apr 21 '17 at 20:13
  • Thanks for the update.. I'm still getting a crash: `*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'Receiver () has no segue with identifier 'chatToInvite''` <- this happens after the menu dismisses itself. For reference chat = origin and invite = destination. – KingTim Apr 21 '17 at 20:36
  • I did set up that `chatToInvite` segue from the chat (origin) to invite (destination), and put your suggested code in the IBAction of the invite button being pressed in the menu. – KingTim Apr 21 '17 at 20:39
  • Are you sure you named your segue in the storyboard? Select the segue in the storyboard, go to Attributes inspector, make sure Identifier is set to "chatToInvite". – Mike Taverne Apr 21 '17 at 20:45
  • I did, double checked that and made sure spelling was correct also: http://imgur.com/a/zF051 – KingTim Apr 21 '17 at 20:46
  • Hmmm... Well the error is very specifically saying it can't find the segue. Are you sure it is wired up from the ChatViewController to the Invite? How are you creating ChatViewController to begin with? – Mike Taverne Apr 21 '17 at 20:51
  • Yeah, I definitely drew the segue from Chat to Invite. And I'm not sure what you mean by how did I create the controller – KingTim Apr 21 '17 at 20:53
  • Is your Chat the initial view controller, or did you instantiate it using UIStoryboard.instantiateViewController(withIdentifier:) or otherwise? – Mike Taverne Apr 21 '17 at 21:07
  • You might also trying cleaning your project with Cmd+Shift+K and restarting Xcode. Something isn't right with the segue setup, and it might not be anything you did. – Mike Taverne Apr 21 '17 at 21:09
  • I don't mention the chat controller in the code at all really, other than when I segue to it from the previous controller in the app with `let chatVc = segue.destination as! ChatViewController` in `prepareForSegue`. And it's not the initial view controller - the app launches on a list of chat rooms (assuming you're already logged in, if not if launches on the login screen). Then when you select a room, it goes to the chat. – KingTim Apr 21 '17 at 21:16
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/142317/discussion-between-mike-taverne-and-kingtim). – Mike Taverne Apr 21 '17 at 21:21
  • not working when present a controller with storyborad name and identification. – Sabrina Nov 10 '18 at 20:59
1

If your presenting view is embedded in a navigation controller then you can do this:

    weak var pvc:UIViewController! = self.presentingViewController?.childViewControllers[0]
    dismiss(animated: true)
    {
        pvc.performSegue(withIdentifier: "SegueID", sender: nil)
    }
Timanious
  • 21
  • 1
0

Simple solution with presentingViewController

if let destinationVC = self.presentingViewController as? YourViewController {
    destinationVC.isBooleanPassed = true
    destinationVC.selectedString = "here comes your string"
    destinationVC.selectedInteger = 12345
}

dismiss(animated: true, completion: nil)
Farkas Antal
  • 310
  • 3
  • 9