Unwind segue doesn't dismiss intermediate ViewControllers - ios

I have a simple app with two ViewControllers. View controller A presents B programmatically (by instantiating it and calling present). Then B, depending on user input, may perform an unwindSegue to A (which works fine) or present another instance of B (again programmatically via present). This can be repeated in a arbitrarily long walk of B view controllers.
The problem is that whenever more than one B instance was shown, the unwind segue works, A comes in with the custom animation I set up for it but then the previous B appears.
A -> B -> (unwind) -> A -- Works fine
A -> B_1 -> B_2 -> ... -> B_N -> (unwind) -> A appears but then B_(N-1) shows.
I tried dismissing B_i when I present B_(i+1), but then all B's are dismissed and I end up in A.
I hope my explanation isn't too convoluted!
I don't know if it makes any difference, but B is a TableViewController and A is a regular ViewController.

Related

How do I return to my primary display (A) if I go from screen A to B to C back to B using unwindSegue

I currently am learning how to program in Swift and have made 3 different pages; Pages A, B, and C. From page A, I am able to navigate to page B, and from page B, I am able to go to either page C or page A. When I go to page C I can go back to page B or page A.
The issue that I am running into however is that if I go from Page A to Page B to Page C back to Page B, when I try to close Page B, it would display Page C briefly before closing back to page A.
All of these are on separate viewcontrollers and I've just been presenting all of them modally each time
I've tried using Unwind Segues Step-by-Step and Create Unwind Segues in Swift 3
to understand what I've been doing wrong, however from what I've read on them (and from my limited knowledge of Swift), none of them discuss going back a single page and then trying to close after. They all go from 1 -> 2 -> 3 back to 1 without the intermediate step of going back to page 2.
#IBAction func close (_ unwindSegue: UIStoryboardSegue){} is what I've been using as my unwindSegues linking these up to my Exit placeholder. This was done on both Pages B and C
Currently there is no error message, it appears to work but it does show that intermediate screen which is not what I am looking for.
Thanks!
You said:
when I tap on the back button on page C -> B it shows that I trigger an Action that presents Modally (if that helps)
That is precisely the problem. Having gone from A to B to C, C should not then modally present B again. You’re creating a new, second instance of B. You’d have a view controller hierarchy that looks like:
A » B1 » C » B2
If, though, you successfully dismissed/unwound from C to B, you would have ended up with only A and B in the view controller hierarchy:
A » B
And then, when B went to dismiss/unwind to A, C would be long gone and there’s no way you’d see it in your animation.
If you’re using unwind segues, I’d suggest that view controller A had an unwind action like so:
#IBAction func unwindToA(_ segue: UIStoryboardSegue) { }
And view controller B could have an unwind action like so:
#IBAction func unwindToB(_ segue: UIStoryboardSegue) { }
Now, when C wants to unwind back to B, if you could use the latter unwind action. If you want to unwind to A (either from B or C), you could use the former one.
Just make sure that you never present/show when you want to go backwards in the view controller hierarchy. Either use unwind segues, or dismiss/pop as appropriate.
I don't really understand your question. But I guess your problem is you used present instead of dismiss when you back to B from C.
Sorry, your question is not fully clear to me . So far I understand if you wanna back from C to B View Controller , then you can do it Simply use
self.dismiss(animated: false, completion: nil)
in Your Exit Button action . Hopefully it will help .
Seems quite confusing question description.
Not sure but maybe you have mistakenly added segue from Page B -> C on the same Back button. Please check that also.
I've created SimpleUnwindExample project on GitHub. Hope It will help in to fix your issue.
Repository Link: https://github.com/harshal-wani/SimpleUnwindExample
Cheers!

Cycles in NavigationController - how to avoid memory leaks?

In my app I have a navigation controller with four controllers. The user navigate from A -> B -> C -> D -> A_1 -> B_2 -> ... etc. It's one way and every ViewController is always a new ViewController.
This cycle is intended. But in ViewController A and C I initialize GoogleMaps which is using a lot of memory. So after 15 loops (and 30 inits of GoogleMaps) my app crashes because of a memory leak.
Now I see different possibilities to solve this problem.
1) I do not init a new ViewController rather I reuse my VCs. So Google Maps just initialize two times.
I dislike this, because my VCs could have different states. A clean init would be more comfortable and a smaller source of errors
2) I remove the stack at the right time, because the navigation is just one way. When the transition from A -> B is done I could throw A away. Same thing for C -> D.
3) I deinit Google Maps after transitions. I don't know how to do this yet but I'm quite sure that I will figure it out.
I read about setViewControllers by which I can replace view controllers.
What is the best practice? What recomments Apple?
Start with the 3rd and the easiest option:
Use override func viewWillDisappear(){} to deinit google maps. You could use this method for 2nd option as well.
But I think, you should use delegates when you go back to A from D. What do you change on A, when you reach it again?
You mentioned that navigation is just one way. If so you can just replace UINavigationController's viewControllers array. In other words, you may not need navigation stack if a user does not go backward in the stack.
Alternatively, I got a similar issue in my app. When I am pushing a controller in the UINavigationController it checks the existing viewControllers and modifies it. For example, if an identical controller is already there, pop to that copy.
You can navigate view controllers from A -> B -> C -> D -> A_1 -> B_2 -> ... etc. using two method.
Method 1:
When you are going to D controller then pop to a specific controller(A controller) and again navigate cycle A to D with the push view controller.
self.navigationController?.popToViewController(A, animated: true)
Method 2:
When you are going to D controller then the present controller (A controller) and dismiss presented cycle flow when you again reached at D controller
viewController.present(A, animated:true, completion: nil)

Unwind Segue or something else?

I am building an app with 6 ViewController (lets call them A, B, C, D, E and F). A is the "Menu" ViewController.
From A you can reach B or F.
From B you can go back to A or go on to C.
From C you can go back to B or go on to D.
From D you can go back to C or go on to E.
From E you can NOT go back to D, but you can go back to A or to B.
From F you can only go back to A.
My question is: Which segues should be 'show' segues and which segues should be 'unwind' segues? Or is there maybe another thing I should do?
Show - forward
unwind - backward
So for e.g. -
when moving from A -> B
use show
now when coming back i.e. B -> A
use unwind.
If you use "show" segue then you will use unwind to go back to any ViewController that has come before it in the view hierarchy but if you use "present modally" then you have to use dismiss to get back. Though with unwind you can go from the latest ViewController to the first most ViewController but with dismiss only the latest ViewController gets dismissed. And you can have as many unwinds as you want as long as you create an #IBAction for each and provide identifier.

How to daisy multiple UIViewController transitions together during unwind

Consider this modal stack
A <-> B <-> C
\--------/\
A can present B or C.
Whenever I need to leave C I need to end up on B,
which means if I got to C from view controller B I can just dismiss.
If I got to C directly from A then I need to unwind back to A and present B.
Bonus points if the latter case can be animated as C -> B transition bypassing the show of controller A.

How to begin next segue before first finishes

There a 3 view controllers in this problem.
I'm using storyboards, segues and UIViewControllerAnimatedTransitioning with the navigation controller to customise the transitions.
I use a custom animation from A -> B, then when that finishes, B -> C animation runs (which is presenting a login form).
What I want is B -> C to start running before A -> B finishes. B -> C runs by calling performSegue in viewWillAppear of B.
I'm sure a UIViewControllerTransitionCoordinator is going to be part of this solution, but I'm just not sure where to attach it in the process.
So what I need to know is, how to begin one segue before the previous one has finished.

Resources