Invoking a UIView Controller from a UIView - ios

I have an initial view controller, say vc1. It has modal buttons, which when selected, takes me to the second view controller, vc2. Inside this view controller (vc2), i have defined a view, say 'view'. Now, After performing some animations, I want to go back to vc1. IS this possible?
I have been able to dismiss the current view using:
[view removeFromSuperview];
But I want to go back to the previous view controller vc1. According to this post: Get to UIViewController from UIView?, I understand that I can get the current UIViewController. But how do I go back to the previous view controller?

First, as discussed in the post you referenced, we "should not need to access the view controller directly", I think this will go on the opposite direction of MVC.
And I am not sure how you want to go back to vc1, is this triggered by pressing some button? If you want to go back, you can do this in vc2 rather than the view. You see, in MVC, views just show UI which view controller tell it to do and responds to actions from user, and then view controller handles all the logic, so when you want to go back to vc1, I think it is proper to place the control code in vc2, just bind some action to the view, like a #selector or a block, then the view in vc2 can trigger this, and there you go.

I think you're getting Views vs. ViewControllers mixed up. I don't think you need vc2 at all.
Try this in vc1:
on button press, create a new view (not a view controller)
add the view as a subview to self.view
do the animation
remove the new view from a completion block attached to the animation

[self dismissViewControllerAnimated:YES completion:nil];
Write this in the animation completion handler or after you remove the view by this your code as you stated,
[view removeFromSuperview];

Related

Is it possible to segue from a modal view to a view that is not in the hierarchy on a Navigation Controller in swift?

On my main view in a NavigationController I have a button that brings up a new view modally to submit a post. I have a button to dismiss this view which brings the user back to the main view, however if the users proceeds to make a post, I want it to dismiss the view and proceed to a show the post in the Navigation controller.
The ideal effect would have the standard navigation controller's back button on the top that can bring the user back to the main view when they have finished looking at their post.
I have tried several different methods, but I tend to get an error stating "Warning: Attempt to present (The View I Want to Show) whose view is not in the window hierarchy!
Thanks for any info!
Yes, it's possible. This is the best way I've found to structure the app to allow this functionality.
RootViewController
UINavigationViewController
ContentViewController (your current "main" view controller)
You're basically going to create a new RootViewController that is going to contain your current UINavigationController as a child. I usually setup the window.rootViewController programmatically in the AppDelegate. I would also keep a global reference to it.
Have a look at Apple's documentation on this. Basically, the RootViewController code would look like this:
[self addChildViewController:navController];
navController.view.frame = self.view.bounds
[self.view addSubview:self.navController.view];
[navController didMoveToParentViewController:self];
Now, whenever you need to present a modal view controller, present it from the RootViewController, instead of the current/top view controller on the UINavigationBar. This allows you to manipulate the UINavigtaionController independently and you won't get the error you're seeing.
So present the modal view controller from the RootViewController, this covers the UINavigationController and its content (top view controller). Make any changes you need to the UINavigationController stack (push, pop, etc...) with no animation. When you're done dismiss the modal view controller (with animation) and it will show you're adjusted UINavigationController.
Hopefully, this all makes sense. It's kind of complex and hard to explain in text. :p
If you don't want to setup a RootViewController, you might want to try presenting the modal view controller from the UINavigationController, as that might have the same effect. From the view controller just do self.parentViewController.present.
The main thing you're trying to avoid is presenting a modal from a view controller and then removing that view controller (pop) before the modal is dismissed. The view controller that presents the view controller is responsible for dismissing it.
I finally got it all working (I'm still new to Swift) and the two comments on the question were very helpful. The most helpful of all was the top answer here's example on github.
Similar question

Dismiss Modally presented view makes tab bar controller (kind of) reset

I have an app which has tab bar controller as main controller. Each tab has a series of views with navigation controller and I normal push and pop those view in stack.
Weird problem is
Case 1 : If I create a UINavigationController and make a new viewController as its root, and present this NavigationController. Within this new navigation stack, I can easily present a view modally and dismiss it without a problem.
Case 2: Now without make a new UINavigationController, I present a view, and when I dismiss a view, the view beneath is behave weirdly. For example, it's the presenting view was UICollectionView, it just scroll back to 1st cell, like it's doing "reload" action and "scrollTo" the first cell. If the presentingView is a pushed view from rootView, it will just popToRoot view, which is definitely not intended.
I didn't have this problem until I implement UITabbarController, so I guess, I should know more that's going on under the hood when presenting a view and dismiss a view in UITabbarController.
I GUESS, when dismiss a view in UITabbarController view, it sort of "RESET" everything to the very first view of it's current tab. I really am not sure it's trure though.
I know it's kind of conceptual, but I can't help to think there must be something critical I am missing here.
I made silly mistake that I sublclass UITabbarController and define navigation controlllers in viewDidAppear instead viewdidLoad, so when I make the window's rootview to tabbar controller, the navigation controllers are not set properly. That's why all punky things happened. It would be nicer if just crash instead of this weird behaviors.
You can try this to go back to your first viewcontroller.
- (IBAction)buttonPressedFromVC2:(UIButton *)sender
{
[self dismissViewControllerAnimated:YES completion:nil];
} // This is going back to VC1.
This method is will be in second viewcontroller.m file. It is button click method.

Going back to main view using the navigation bar back button

My app has a main view with a few buttons lined up vertically. Each button is linked to a different view controller. Now, when the user taps on the first button, the first view controller is opened. Within the first view controller, there is a button which takes you directly to the second view controller. When I get to the second view controller, and press the back button, I am taken back to the first view controller. Then I have to press the back button one more time to be taken to the main view controller. What can I do to make the app take me directly to the main view controller from the second view controller, and not through the first view controller? Thanks in advance!
You could bypass the segue_unwind to go back to the main view controller. Just call the performSegueWithIdentifier in the IBAction of the button
Swift
self.performSegueWithIdentifier("SegueIdentifierName", sender: self)
Objective C
[self performSegueWithIdentifier:#"SegueIdentifierName" sender:self];
Here is a similar article as well
What are Unwind segues for and how do you use them?
You can override the back button action to call popToViewController() on the navigationController with the view controller you would like to return to.
There are a lot of answers in SO about this BUT:
[self.navigationController popToRootViewControllerAnimated:YES];
OR
UIViewController *rootViewController = [self.navigationController.viewControllers firstObject];
[self.navigationController pushViewController:rootViewController animated:YES];
Should work just fine.
Next time, TRY to find answers first:
How do I get the RootViewController from a pushed controller?
SWIFT 3.01
self.performSegue(withIdentifier: "SegueIdentifierName", sender: self)

Bypass UIView without showing

I am using Storyboards for an iOS 7 App. The root controller is a menu. For almost every view, I have a Menu button which brings the App back to that menu using [self.navigationController popToRootController:TRUE]. However, there are two UIView elements where I would like to clear the Navigation Controller view list (as happens when you pop back to the root controller), but then immediately go to another UIView without having the user see the root controller's view. Once at this new view, if the user presses the back button, I want them to go to the menu view.
I've tried to put a performSegue in the viewWillAppear, but it really messes up the Navigation Controller and views. I've tried putting a performSegue in the viewDidAppear, but the user sees first the Menu view flash in, then out on it's way to the correct view.
I hope I've explained this well enough. I hope this can be done.
Thanks.
Your best bet is to build the navigation controller stack yourself, and then use - (void)setViewControllers:(NSArray *)viewControllers animated:(BOOL)animated: to replace the current stack.
So you could do something like
...
UIViewController *vcToPush = ...;
NSArray *newVCStack = #[[self.navigationController.viewControllers firstObject], vcToPush];
[self.navigationController setViewControllers:newVCStack animated:YES];
This will add your new controller to the stack using the standard push animation (or not if you so choose), and after the animation is complete, set the view stack to that of the array.

How to dismiss a NavigationController in Storyboard?

I've looked everywhere for this, so as a last resort I figured I should ask the question.
I'm using Storyboard in XCode and have a navigation controller as my initial view. The root view of this navigation controller is a table view. In this table view, I have a button in the navigation bar that flips the view horizontally via a modal segue to a navigation controller. The root view of this controller is my map view. Now, when I want to dismiss this map view using [self dismissViewControllerAnimated:YES completion:nil] it doesn't work. It does if I take out the navigation controller. So, I'm guessing the dismissViewController is getting passed to the navigation controller, and not doing anything. I know I could implement a class for the navigation controller to handle the call and pass it on, but I don't want to do that unless absolutely necessary.
So to solve this question:
I need a way to switch between table view to map view using the flip horizontally animation and vice versa.
I need to have a navigation controller in both views, I could either be the same one, or a different one. I can't seem to find a way to use the same one, since any transitions would be pushes which don't do the flip horizontally transition.
Thanks in advance for the help!
Who is self when you call [self dismissViewControllerAnimated:YES completion:nil]?
The receiver of this message needs to be the view controller which presented the modal view controller you want to dismiss. If you call it on the presented view controller, or (in the case of container view controllers like UINavigationController, one of the view controllers it manages), UIKit will try to do the right thing but won't always succeed.
Presuming the self you refer to is the view controller containing the map view, you can get the presentingViewController property to get the object you should call dismissViewControllerAnimated:completion: on. (And if you need to get the navigation controller that's in between, use the navigationController property.)

Resources