Dismiss view controller from unwind segue - ios

I have 3 view controllers. I can go from A to B, then from B to C. I've made an unwind segue from B to A. When it's performed, I can see that view controller B has been deallocated, and VC A appears on screen.
To make it I added next code to VC A and made unwind segue on button in VC B.
#IBAction func unvindSegueToMenu(segue:UIStoryboardSegue) {}
However, when I go to VC C (from B) I want to perform unwind Segue from VC C to A. To do that I put next code to VC B class.
#IBAction func unvindSegueToMainMenu(segue:UIStoryboardSegue) {
self.dismissViewControllerAnimated(false, completion: nil)
}
After I press button in VC C, it shows me VC A as I want, but in Allocation Summary I can see that VC B has not been deallocated.
What is my mistake and how can I deallocate it?

Normally you made something wrong in your code.
i tested and i can see clearly that VC B is deallocated after performing the unwind segue.
First be sure that you made it right. (for example the performed method of the unwind segue should be implemented in the destination VC)
Also you can check after performing the unwind how many viewControllers you have in the navigationController..in your case should be 2 , but if you do it in the right way it will be only one.

Related

Swift 5 - Middle view controller briefly appearing - Should remove?

Setup:
Initial view controller A has a menu button that goes to VC B, which then has a button that goes to VC C. On C, I have an exit button that takes me back to A. In this transition, B briefly appears. The two things I'm trying to figure out is:
How do I keep B from flashing on the screen?
and
Is B off the call stack and releasing the memory?
This is what I'm running to get rid of the C and go back to A:
#IBAction func backButtonPressed(_ sender: Any) {
self.view.window!.rootViewController?.dismiss(animated: true, completion: nil)
//performSegue(withIdentifier: "exitToMainScreen", sender: self)
}
I found a work-around for this glitch.
In VC B, I encapsulated everything in a view attached to an outlet. So when I perform the segue to VC C, I set the view's isHidden = true. When the unwind from C to A occurs, the view in B is hidden and does not appear on the screen in transition.

Double return to previous view - Swift

I'm new with IOS and Swift so don't judge if solution is easy.
I have three ViewControllers like A,B and C.
I started from A -> NavigationController -> B -> NavigationController -> C
In specific situation I need to come back from C to A without seeing B. Is any way to do this?
Maybe changing the parent navigationController? Maybe I can print stack with every current view? - it will be really helpful.
I tried dismiss C and B view one by one and it work's but then we can see B view for a moment - so it's not a solution for me.
P.s : I'm using Modal kind to switch between controllers.
enter image description here
If A is always the first view controller, you can just do :
viewcontrollerC.navigationController?.popToRootViewController(animated: true)
This methods pop the stack to the first view controller, without displaying intermediates ones
If A is not the first viewController, you can do :
viewcontrollerC.navigationController?. popToViewController(viewControllerA, animated: true)
If you don't have a reference to viewControllerA, search it in the stack :
let viewControllerA: UIViewController?
for (let vc in (self.navigationController?.viewControllers ?? [])) {
//adust the test to find the appropriate controller
if vc.isKindOf(ViewControllerAClass.self) {
viewControllerA = vc
break
}
}
if let viewControllerA = viewControllerA {
self.navigationController?.popToViewController(viewControllerA, animated: true)
}
source : https://developer.apple.com/documentation/uikit/uinavigationcontroller/1621871-poptoviewcontroller
There are 2 ways you can achieve this. The simple to implement is in View Controller C you can, on in the specific situation, invoke following function:
navigationController?.popToRootViewController(animated: true)
This will pop all the navigational view hierarchy and take you back to the root i.e. the first view controller.
Second approach is to define unwind method in the view controller you want to go back to. In view controller when you start typing unwind, in Xcode 10 you will get autocomplete to add this Swift Unwind Segue Method.
#IBAction func unwindToA(_ unwindSegue: UIStoryboardSegue) {
let sourceViewController = unwindSegue.source
// Use data from the view controller which initiated the unwind segue
}
In this particular question let us say you added this method in View Controller A as you want to go back to it. I assume you have a button on View Controller C to go back to A. Controll+Drag from the button to the Exit symbol of the view controller A. The unwindToA method will automatically pop-up. Connect to it and you are done. When the user presses this button it will go back 2 navigation controllers to A.
Note: By this method you can go back to any navigation controller on the Navigation stack and it is not limited to root view controller alone. Below I am addition picture showing the exit on a view controller.

Unwind multiple navigation controllers

Say I have view controllers A, B & C embedded in a navigation controller. From C, I present a new navigation controller for a separate logical flow but need to return back to A upon completion. So the app flow is as follows: A->B->C -- present new navigation controller modally -- D->E->F. Then go from F back to A.
I have set up an unwind segue, however, the unwind segue only takes me back to D even though I have set it up to return back to A.
How can I make it unwind all the way back to A? Am I missing something I don't see? Thank you.
Inside A:
#IBAction func unwindToHome(segue:UIStoryboardSegue){}
Then I have control-dragged from F to its 'exit' and chose the unwind segue I created in A, and wrote this segue code:
private let SEGUE_TO_HOME = "unwindToHome"
performSegue(withIdentifier: SEGUE_TO_HOME, sender: nil)
When you unwind, it should go back up the chain of view controllers, through all of those navigation controllers and modal presentations, to get all the way to the view controller that has this unwind action implemented.
Is it possible that unwindToHome occurs in any of these view controllers other than A? That's the only way I can see that the unwind action wouldn't sent you all the way back to A. I'm wondering if, for example, D has its own unwindToHome action (or perhaps is another instance of the same type as A). Bottom line, I cannot reproduce the behavior you describe except through something like that.
You subsequently asked:
I have put a deinit method in all of the above view controllers. I only print the word gone in all of them. when it unwinds back to A, 'gone' is only printed twice. Doesn't the unwind segue deallocate all instances?
Yes, they should all be deallocated. If not, the “debug memory graph” (see https://stackoverflow.com/a/30993476/1271826) is excellent at showing what is keeping a strong reference to the ones that are not deallocated. Most likely, these un-deallocated view controllers have some lingering strong reference cycle, repeating timer reference, or something like that which is keeping a strong reference to each, respectively.
You could simply create a reference to the first navigation controller that controllers A-C are embedded in by creating a subclass for the second nav controller.
class SecondNavController: UINavigationController {
// getter for previous nav controller
var prevNavController: UINavigationController? {
return parent?.navigationController
}
}
and when you need to unwind, simply:
class FController: UIViewController {
// other code
func unwindToRootController() {
guard let navController = navigationController as? SecondNavController,
let prevNavController = navController.prevNavController else {
return
}
navigationController.popToRootViewController(animated: true)
}
}

xcode 8 swift: unwind segue transfer data is not working

So I have been trying to get a unwind segue to work from last two days. I have tried watching and follow several different tutorials and none was successful. I created the #IBAction override func unwind(for unwindSegue: UIStoryboardSegue, towardsViewController subsequentVC: UIViewController) but this never performs any of the code. I put a simple print and had it print text, it never printed the text. I created that in the first View Controller then in the second View Controller I had a button that I connected to the Exit at the top of the View Controller and selected the unwind action and it never unwinds. What am I doing wrong or missing?
So here is what I have so far I have 2 views: RaceViewController & SingleStatViewController
I will start by selecting specified rows in RaceViewController and they will open SingleStatViewController modally. I have a button in SingleStatViewController called dismissBtn. When I click the button it dismisses SingleStatViewContoller. I just need it to pass some data back to the RaceViewController.
So if the user selects 1 of 3 cells in the table (the rows are Half-Orc, Half-Elf and Human) it will open SingleStatViewController and ask to select 1 stat (these will be of 6 buttons (Str, Dex, Con, Int, Wis, Chr) when they select the one of the buttons it will return the data and update the detailTextLabel.
I select Human then I select Str. When it gets back to RaceViewController and it updates the text in the detailTextLabel to +2 Str.
Right now, this is the code I am using to dismiss. Can I use this to continue or do I actually need to perform the unwind:
#IBAction func dismissbtn(_ sender: Any)
{
dismiss(animated: true, completion: nil)
}
You need to perform unwind and send data as following:
#IBAction func unwindToRaceViewController(sender: UIStoryboardSegue)
{
if let sourceViewController = sender.sourceViewController
as? RaceViewController {
stat = sourceViewController.stat
}
You could refer to this article for unwind segues as alternative to delegate
You could also use delegates to pass data back to the previous controller.
Okay, so you have vc A and vc B, this is what you need to do to use unwind segue:
In vc A, create a segue function eg. #IBAction func unwind(segue: UIStoryboardSegue)
In vc B, write code that call self.performSegueWithIdentifier("unwind", sender: self) (assume that the identifier and the function name is the same - call this in your dismissbtn)
In vc B in storyboard, look on top of it, there will be an yellow button and 2 orange button, hold and drag the yellow button to the Exit orange button, choose the action that you created in vc A, give it an identifier as mentioned
In the unwind func, the rest is the same as normal segue when you pass data forward, just change destination to source and you must present vc B from vc A, else then use delegate

Unwind to specific instance of ViewController

I have a ViewController that I'm just re-instantiating to navigate to another instance of it (there's a reason for this) with the following code:
let viewController = storyboard.instantiateViewControllerWithIdentifier("CompletionViewController") as! CompletionViewController
self.navigationController?.pushViewController(viewController, animated: true)
Everything works fine, except when I try to unwind... since every instance of the control has the unwind method:
#IBAction func unwindToThisViewController(segue: UIStoryboardSegue) {}
It ends up unwinding to the last instance of the VC instead of the first (which is what I want), for example:
vc1 > vc2 > vc3 > unwind from here
I want to unwind to "vc1", but it actually unwinds to "vc3".
Is there anyway that I can unwind to the first instance of the VC; or like in my example "vc1"?
in your CompletionViewController, there are 3 icons at the top of the view. if you CTRL drag from the left yellow icon to the right red one (the "exit") you can choose your unwinding segues. Now you can use that unwind in your code ;)

Resources