How to unwind segue several steps back? - ios

There are a lot of stuff on the net according the topic but I don't get it. I have an App with Custom segue implementation and without Navigation controller. There are cases in which I need to unwind back several steps.
For implementation I use simple calls:
CODE CUSTOM SEGUE
For wind:
[[self sourceViewController] presentModalViewController:[self destinationViewController] animated:YES];
For unwind:
[[self destinationViewController] dismissViewControllerAnimated: YES completion: nil];
As I understand when I wind segue somewhere in the memory there is data which is used during the unwind. For that reason in the custom unwind I only use read only property destinationViewController.
So how can I unwind several steps back in one action? Or I have to make several unwinds in different View controllers?
I read the following question, but I don't understand implementation.
Bellow I put example of my apps logic:
EXAMPLE
I have 4 VC which is in a chain:
VC A -> VC B -> VC C -> VC D
I wind and unwind back and forth. The logic is ok. There are situation in which I need to unwind back from VC D to VC B. How to do that? Can I unwind directly to VC B or I have to unwind to VC C and then in the unwind handler to unwind to VC B?
I also thought of additional segue from VC D to VC B, but there are remarks on the net that this is not the right way, because segue chain will get messy.

The answer to What are Unwind segues for and how do you use them? has everything you need to know about unwindSegues (I suggest you re-read it).
But for a more direct answer, yes you can unwind back from VC D to VC B. To do that you have to first implement the method in VC B:
- (IBAction)unwindToVCB:(UIStoryboardSegue *)unwindSegue
{
}
after doing so, go to the IB, and control-drag a button's action to the Exit icon, you should then pick the method you created above as the selector. (This is taken directly from the question/answer stated above).
Again, for a clearer version of what I said, read the answer of the linked question I mentioned above.

You have to use UINavigationController, just add it in storyboard as mainViewController and set 'A' ViewController as root view controller for it, then change all segues to push segue, set 'Identifires' for them, and you can use performSegueWithIdentifire to push view controller and inside view controller:
[self.navigationController popViewControllerAnimated:];
or
[self.navigationController popToViewController: animated:];
to dismiss it.

Related

Does an unwind segue release memory use of intermediate VCs, if no navigation controller is used? [duplicate]

I have an iPad app which has a lot of screens and a lot of segue options.
At the moment, I am simply using performSegueWithIdentifier to initiate these segues, and my fear is that I'm taking up a lot of memory as the user performs more and more segues.
I've seen that people recommend using the function popToRootViewControllerAnimated: if using a UINavigationController, but the problem is that I'm not using one.
How can I stop the number of VC's proliferating?
The way the app works, the user does constantly return to the root VC - effectively a search screen. So if I could clear the stack of VC's when such a segue is needed, that would solve my issue I think, but I have no idea how to go about this.
Thanks for any suggestions.
When you are using segues the flow moves backwards and forwards. When the user moves backwards (ie presses "back") then it will not push to a new VC but it will pop to a VC that already existed. When you pop, the current VC is removed from the stack and memory.
If you have segues to move backwards in the flow then this is wrong. You only need segues to move forward.
A PROPER PREPARE FOR SEGUE
In prepare for segue you should never create your own view controllers and push to them. The storyboard is there to do all of this for you.
A proper prepareForSegue method should look something like this...
- (void)prepareForSegue:(UIStoryBoardSegue*)segue
{
if([segue.identifier isEqualToString:"SomeSegue"])
{
MyNewViewController *controller = segue.destinationViewController;
controller.someProperty = "some value to pass in";
}
}
That is all you need. Note that you only need this if you intend to pass some information to the new view controller. If you are not passing anything forward then you don't need this method at all.
When the method ends the new VC will get pushed onto the screen by the storyboard file.
UNWIND SEGUES
If you have a random flow (like in your comment) then you can use unwind segues to achieve this.
In you 'A' view controller have a function like...
- (IBAction)someUnwindAction:(UIStoryboardSegue*)sender
{
//some action to run when unwinding.
}
It needs to receive a UIStoryboardSegue object. If set up as an IBAction you can also access it from Interface Builder.
Now when you want to go A > B > C > B > A then just used the standard push and pop (from the segue and back button).
When you want to go A > B > C > A then you can use the unwind segue from controller C.
If you have a cancel button or something in controller C and this is in the Interface Builder and this should take you back to controller A. Then in the Interface Builder underneath controller C you will have a little green square with a door and an arrow pointing out of it. Just point the action of the cancel button to this symbol and choose "someUnwindAction". (Note, unwindAction is in A, button is in C.) XCode then uses this to pop you all the way back to A and deals with removing any memory and stuff. If you want you can send additional information back to A too.
If you want to access this unwind segue from C programmatically then you can run...
[self performSegueWithIdentifier:"someUnwindAction" sender:nil];
This will also pop back to A.
imho I don't see any issues with using segues, it is much more simple than anything else. If you worry about memory consumed then just profile your app and see how much it eats and how often your "memory pressure handler" is called.
ok I believe I've figured this out. It appears to work.
Since I keep returning to a common VC, I am placing code in the places where I want to segue back to this 'root' VC to clear the VC stack.
I still perform the actual segue in my normal code
[self performSegueWithIdentifier:#"editBackToSearch" sender:self];
However in the 'prepareForSegue:' method, I no longer create a new VC object, instead I perform any work I have outstanding (save my data), and then clear the VC stack with the following code.
UIViewController *vc = self;
while ([vc presentingViewController] != NULL)
{
vc = [vc presentingViewController];
}
[vc dismissViewControllerAnimated:NO completion:nil];
It appears to run smoothly and has the desired impact (confirmed via the profiler) of releasing the memory that these VC's sucked up.
One last comment - for some reason I could not animate the dismissal command, this appeared to trigger an infinite loop and resulted with an EXC_BAD_ACCESS. With animation set to NO, it works great though.
Thanks for your help.
Swift 3: this is to prevent memory leaks in Swift 3 & 4
#IBAction func entryViewSelected(_ sender: UIButton) {
self.dismiss(animated: true, completion: nil)
}

Whats the difference between moving between Storyboard scenes - Segues and Unwind

I'm a fresher. I used segue to go (Flow of Execution) such like that
UIViewController A => UIViewController B => UIViewController C.
And used unwind segue to move from C to A. But I am confused about how they different of each other.
And Why I use unwind segue although I have delegation.
Thank You in advance.
Regular Segue allows us to send data from one view controller to another, but it’s not easy to bring data back if the user has changed or added details in that view controller. That’s where an Unwind Segue comes in.
Read more here
Segues are for presenting a new view controller.
Unwind Segue is a special kind of segue (A go back mechanism) which moves back to the connected destination.
A->B->C->A
If you are using segue for above mentioned flow, there will be two different instance of A in the memory.
If you use unwind segue for the C->A transition
It act as a go back mechanism and it removes the C and B instance from the memory once the segue is over
There will be only 1 instance of A

iOS8: Pushing View Controller in prepareForSegue for another flashes it

I have 3 View Controllers, conveniently named A, B, C.
A is presented using a UINavigationController, and has a push segue to C.
My desired effect is that after performing the segue, C's back button will pop us into B, and then B's back button pop us to A. Effectively, this means that segueing to C will put both B and C onto the stack.
in iOS7, I've used the following (redacted) code successfully:
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
CViewController *slotViewer = segue.destinationViewController;
/* Do Stuff */
BViewController *controller = [self.storyboard instantiateViewControllerWithIdentifier:#"B"];
[self.navigationController pushViewController:controller animated:NO];
}
The result appearance was a smooth transition from A to C, while B is loaded and B's ViewWillAppear is only called when clicking on C's back button.
However, on iOS8, this breaks: The transition briefly flashes B on the screen, its viewWillAppear is called, and only then C is shown.
Any idiomatic way to perform this transition in iOS8?
I know I can use the method described here but it feels awkward, and I'd rather use the Segues all the way.
The method (setViewControllers) you linked was designed to do exactly you want. Why is it awkward? It's provided by Apple.. Besides that there is no way to use segues only. Your previous solution was same like pushing first one programatically and right after second one by interface builder..this is awkward man:).
Please don't do this. You're not supposed modify the navigation stack like that! It's awkward.

How to push some viewcontrollers with segue at a time

When the NavigationController has 3 view controllers (A,B,C).
I want to move to the view controller C from A via B with using a segue at a time.
In this case, what's the best practice?
I believe you need perform seque B->C manually once seque A->B is finished (for example in viewDidAppear).
Use this code:
UINavigationController *navController = [self navigationController];
[navController performSegueWithIdentifier:#"SegueIdentifier" sender:self];
I assume you have a segue with appropriate identifier.
I can not understand the logic to go A-C but moving the way A-B-C.
but this can be done perform seague A-B . in B use the method viewWillAppear() or viewDidload to perform the segue for C .
Hope this will solve your problem.

UIStoryboard popViewController

I'm using a UISegue in my application to automatically transition between viewcontrollers in my application. I'll call them A and B.
It worked as expected, however when I wanted to pop-back to the A from B, I attempted to call
[self.navigationController popViewController] however the B's navigationController property reports null.
As a second attempt I attempted to map a button, to a UISegue back to view controller A.
However this just creates a new ViewController.
As a work around, I ended up doing as a work around was to retrieve the B viewcontroller from the UIStoryboard and calling [A.navigationController pushViewController:B]
At which point, calling [B.navigationController popViewController] worked as expected.
This seems wrong, from a storyboard segue how can I return to the previous view controller?
I don't know about the class of your A and B controllers (whether UIViewController, UITableViewController or UINavigationController), but if you follow the following pattern, it should work.
In an empty storyboard, insert a UINavigationController. This will bring in two windows to the storyboard, linked with an arrow (a segue). The one on the right should be controller A.
In A, let's say, you add a button. The button will push B into the navigation stack.
Then, you add the second controller B, and drag from the button in controller A to controller B, and choose "push" from the popped menu.
If you only use a UIViewController (A) and push B, there is no navigationController to take care of popping.
Hope that help.

Resources