poptorootviewcontroller and instruct rootviewcontroller to perform some action - ios

I have a navigationcontroller, and under that I have controller A as rootviewcontroller and controller B is linked to A through a default push segue.
What I want to do is to when some action is pressed in B, I will ask the navigation controller to pop to rootviewcontroller, which is A, and apply some popovercontroller(or just another view or another window) on top of A.
Someone suggested me to ask appdelegate to create another window on top of current uiwindow. I think it is possible and I want to know if there is any simpler/more elegant solution for this problem.
a general solution of what I can do will be appreciated and some simple code samples in Swift will be much more appreciated :P

I will just provide my own answer here.
According to my own experience, there is no popping segue and therefore we cannot exactly get destination view controller from segue. however, UINavigationController has an attribute viewControllers which basically are all children controllers on the stack.
so before popToRootViewController, just get the VC but calling self.nagivationController.viewControllers[0] and you get the root view controller already

Related

Correct way of removing (deleting) a view/viewController from the stack after segue in Swift

I am running into a problem here. I am presenting views with performSegueWithIdentifier. Everything goes smoothly. The problem is that as a test, I only have 2 viewControllers with some data in them and I have two buttons that call a segue back to the other VC. If I keep performingSegues, you can clearly see that the memory usage goes up every two segues by around 0.4Mb. This tells me that the Views are not being deleted/removed from the view stack and are just using memory. I would like to know the correct way of getting rid of the view that presents the other view by using performSegueWithIdentifier (of course, after it finished presenting the view, else it will not work I guess).
Could you point me in the right direction? I found some objective-c code that tried to do this but it was very extensive and I don't know much about objective-C, so it was a little hard for me to understand.
Thank you in advance for your help!
Cheers!
Edit:
I am doing a "manual segue". By this I mean I have two view controllers standing on their own. They are not embedded in any navigationVCs or something like that. I am using an "Adaptive Segue" of type "Show".
If your goal is to always keep one VC, and since you already have a manual segue, what you can do is, after presenting the next VC you can pop the existing VC from the root and assign the destination VC as your root VC like so
class ManualSegue: UIStoryboardSegue {
override func perform() {
sourceViewController.presentViewController(destinationViewController, animated: true) {
self.sourceViewController.navigationController?.popToRootViewControllerAnimated(false)
UIApplication.sharedApplication().delegate?.window??.rootViewController = self.destinationViewController
}
}
}
When you do normal segues, you are piling up new view controllers on top of the existing ones without dismissing them. That's why your memory usage keeps going up.
You need to provide more information before we can give you specific guidance. Are you doing modal segues or pushing onto a navigation stack?
If you're pushing, you want to pop to the view controller you came from. Think in terms of a stack of plates. When you push, you add plates to the stack. When you pop, you take plates off and reveal the plates (view controllers) underneath. Do a search in the Xcode help system on "PopTo" to find the methods that let you either pop back to a specific view controller or back to the root view controller of your navigation controller.
Modal view controllers stack on top of each other in a similar fashion, but without the origination of a navigation controller. If you've pushed a series of one or more modals and you send the dismissViewControllerAnimated:completion: method to the view controller you want get back to it will dismiss the modals that are on top of it.
You can also look at using unwind segues. Unwind segues let you go back where you came. Do a search in the Xcode help system on "Using unwind segues" for more information. Most of the tutorials on unwind segues are written in Objective-C but you should be able to find some in Swift if you look. Explaining unwind segues in enough detail to be useful is more than I can cover in this answer.

UIStoryboard Show (e.g. push) simple inverse action to go back

In storyboard we have great feature that allow us to make Show (e.g. push). So seems the logic is next:
If we don't have navigation controller then view controller will use present modal logic. My question is there any inverse action that I can use with Show?
I have a UIButton that close current view controller screen:
- (IBAction)onTappedCloseButton:(id)sender
{
[self.navigationController popViewControllerAnimated:YES];
}
But in case if I don't have navigation controller, how can I simple use inverse action to go back? So my solution is to check if self.navigationController is nil then use dismissing option:
[self dismissViewControllerAnimated:YES completion:nil];
But maybe there is another cool solution like Show (e.g push). But Close (e.g. pop)?
Yes, you can use an unwind segue to go back, and it will be the reverse of whatever the forward segue was.
You have two options on how to do this:
1) The Unwind segue
To make an unwind segue you have to add a method in the view controller you want to "unwind" to with the following format:
-(IBAction)someSelectorName:(UIStoryboardSegue *)sender;
You will then be able to drag from your UIButton up to the "exit" icon in your storyboard.
Wire it up to the selector you just defined and UIKit will figure out how to get back to that view controller without you having to write any code. This can be especially useful as it can figure out when it needs to call -dismissViewControllerAnimated: more than once and can call those methods successfully. It can even unwind from within a view controller embedded in a navigation controller when the view controller you're unwinding to has the navigation controller presented on top of it. (i.e. it will do a dismissViewController instead of a pop to unwind)
2) The Custom unwind method
Say you don't want to or cant trigger this action from a storyboard. There is still an option and its detailed over at this question here:
Whats the programmatic opposite of showViewController:sender:
The gist is you can write your own generic dismiss method by implementing categories on the UIKit container View controllers (or on your own container)

Segue to a viewcontroller in another storyboard without a navigationcontroller

I want to move to another viewcontroller in another storyboard and the view controller im in is not embedded in a navigationctroller.
Normally i would just instantiate the viewcontroller and push it to the navigationcontroller stack but since this is not possible i dont know what to do, and I cant seem to find any help on this.
Any suggestions?
It depends on what you're trying to achieve in the app, but a few options are: present it as a modal controller, create your own custom type of segue, replace the root controller in the app's window....

iOS Showing views conditionally

I have a view in which a user selects an action to take and on that next screen there is a save and a back button. For both of the buttons the last line is dismissViewControllerAnimated:.
I need a way to make the 1st screen show only if the back button is used. save should send back to the main screen/rootViewController I am fairly new to iOS but not programming in general and just need a nudge in the right direction.
Could I set a bool flag to show or not? Maybe I can set the Tag on the view and then check that in the other screens on save/back? I assume I can check the parent view.
Sorry if this is a dup but I cant find anything specifically for this.
EDIT: I am not using a nav controller and am showing the views modally.
The answer will vary depending on how your UIViewControllers are structured and setup. If you're using a uinavigationcontroller then you can POP to the root view controller using:
[self.navigationController popViewControllerAnimated:YES];
If you're presenting your UIViewControllers modally, you can try to dismiss the presenting View Controllers of your modal view controller using the presentingViewController property:
[[[self presentingViewController] presentingViewController] dismissViewControllerAnimated:YES completion:nil];
You may also want to take a look at Unwind Segues if you're using a Storyboard:
What are Unwind segues for and how do you use them?
Finally, as far as determining whether the back button is pressed or another button - that depends on how the app is setup. You'll need to use your own logic (probably if / then statements or case / switch) to determine which button was pressed. You also may want to check out the sender argument in IBActions.
John, to have a UINavigationViewController return to it's root viewcontroller, you use:
[nameOfNavController popToRootViewControllerAnimated:YES];
The other guys are correct that the information you've provided is definitely not enough to determine exactly what you need to do.
You can use the presentingViewController property of a modal view controller to access it's presenting controller.
It turns out that I was using the terminology wrong. I am presenting all views modally and that is the issue, there is no navigation controller. I ended up using NSNotification to build a listener and had the main view controller listen and then dismiss the view and hence show itself. Worked a treat.
here is the link to the code I ended up with.
http://iphonedevsdk.com/discussion/114737/view-heirarchy-issues-possibly-from-the-camera
Hopefully this helps someone else.

Manipulating view hierarchy by code

If I have a UITabBarController (2 tabs) as root view controller then in the first tab (FirstTabViewController) I init a UINavigationController with a root view controller AddReminderViewController and present it.
Then inside AddReminderViewController I present another UINavigationController with a root view controller called ChooseOptionViewController and present it.
Now when I'm inside ChooseOptionViewController I want to programtically go back to FirstTabViewController how can I do this as easy as possible? Do I need to - dismissViewController... on all view controllers that I have presented or is there an easier way?
Also inside ChooseOptionViewController how can I find out the class that presented ChooseOptionViewController? I tried doing [self.presentingViewController class] but that just says UINavigationController (not AddReminderViewController)
Now when I'm inside ChooseOptionViewController I want to
programtically go back to FirstTabViewController how can I do this as
easy as possible?
You really ought not to have the ChooseOptionViewController try to manage all that by itself. It should simply tell its parent that its job is done and let the parent dismiss it. The parent could then tell its parent that its job is done, and so on. This approach will make it much easier to maintain your code, and to change things around when you decide that's necessary, without breaking ChooseOptionViewController.
For example, imagine that AddReminderViewController wants something else to happen, like presenting ChooseMoreOptionsViewController after ChooseOptionsViewController has been presented. If AddReminderViewController is in charge of the flow of its part of the program, that's easy. If ChooseOptionsViewController knows enough about the reset of the app to dismiss view controllers all the way back to FirstTabViewController, you'll have to modify it every time there's a change in the flow. That's not a recipe for long term success, and it adds a lot of unnecessary and unhelpful complexity.
generally unless an exception you should use only one navigation controller.
keep pushing view controllers onto it.
in that way you can move pop top to root view controller.
for ex:
1
just add one navigation controller to tab 1
2
setrootviewcontroller of navigation controller to FirstTabViewController
3
from FirstTabViewController you can push AddReminderViewController(using the same navigation controller)
ex:- [self.navigationController PushViewController:....];
4
from AddReminderViewController you can push ChooseOptionViewController(using the same navigation controller)
ex:- [self.navigationController PushViewController:....];
5 finally use [self.navigationController popToRootViewController];

Resources