Removing ViewController after showing modally a second ViewController - ios

Guys in my app I have some code in the app delegate method application:didFinishLaunchingWithOptions: that determines if the initial View Controller should be the LoginViewController or the MainViewController.
If the LoginViewController is showed first and the user logs in successfully I show the MainViewController modally with this piece of code:
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
FSMainViewController *vc = (MainViewController *)[storyBoard instantiateViewControllerWithIdentifier:#"MainViewController"];
vc.loginViewController = self;
[self presentViewController:vc animated:YES completion:nil];
What I want to do next, after the MainController is showed on the screen, is remove the LoginViewController from memory so in the viewWillApper:animated: method of the MainViewController I use this code to remove (or at least try to) the LoginViewController:
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
if (self.loginViewController) {
[self.loginViewController dismissViewControllerAnimated:NO completion:nil];
}
}
Problem is that this code leads to strange behaviors like the MainViewController being removed from the screen and this error message showing up in the console.
Unbalanced calls to begin/end appearance transitions for <LoginViewController: 0xb06e350>
I also tried calling [self dismissViewControllerAnimated:NO completion:nil] in the completion block of the presentViewController:animated:completion method but still no luck, it didn't work.
What am I doing wrong? How can I remove from memory the underlying LoginViewController when the MainViewController is presented modally?

Don't present your main view controller if you want the login controller to go away, just make it the window's root view controller.
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
FSMainViewController *vc = (MainViewController *)[storyBoard instantiateViewControllerWithIdentifier:#"MainViewController"];
Self.window.rootViewController = VC;

You can't dismissViewController after presenting another one on it or its presentingViewController. At here, you should dismiss LoginViewController first, then present MainViewController.
Otherwise, if you'd like pushViewController, you can call [self.navigationController setViewControllers: animated:] to remove LoginViewController.
If you think presentingViewController is just what you want, try something like this in application:didFinishLaunchingWithOptions:
if (self.loginViewController) { //Define loginViewController in appDelegate.h
[self dismissViewControllerAnimated:NO completion:^{
[self presentViewController:mainViewController animated:YES completion:nil];
}];
}
else{
[self presentViewController:mainViewController animated:YES completion:nil];
}

Related

Warning “attempt to present ViewController whose view is not in the window hierarchy - Objective C

I'm trying to call a controller, if has response error, and redirect the user for login controller.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"EventManagerStoryboard" bundle:[NSBundle mainBundle]];
LoginViewController *loginController = [storyboard instantiateViewControllerWithIdentifier:#"loginID"];
[loginController viewDidLoad];
loginController.showOnlyLoginForm = YES;
[self presentViewController:loginController animated:YES completion:Nil];
and I facing this warning -
Attempt to present Attempt to present LoginViewController: 0x7fc958201130 on ProfileController: 0x7fc9583118e0 whose view is not in the window hierarchy!
Don't run this code in viewDidLoad try it in viewDidAppear
[self presentViewController:loginController animated:YES completion:Nil];
Edit:
use in appDelegate if you implement navigationController
[(UINavigationController *)self.window.rootViewController pushViewController:vc animated:YES];

Showing view controller from AppDelegate when notification arrived

I am tring to show UIViewController which is inside the UIStoryboard. There isn't any problem about poping up the view. But the navigation is not working in the popup viewcontroller; such as when I touch back button
[self.navigationController popViewControllerAnimated:YES];
I am using that code in AppDelegate --> didReceiveRemoteNotification method
UIStoryboard *mystoryboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
PFProfileInfoVC *viewcontroller = [mystoryboard instantiateViewControllerWithIdentifier:#"SBID_ProfileVC"];
viewcontroller.strAuthorID = [userInfo objectForKey:#"aps"][#"targetId"];
[self.window.rootViewController presentViewController:viewcontroller animated:YES completion:nil];
Thanks,
When you use presentViewController, the viewController is not pushed onto the navigation stack. Normally, it is presented modally. So if you want to dismiss it, use
[self dismissViewControllerAnimated:true completion:nil];

Need to return to the presenting UIViewController from within a presented UINavigationController

In MyMainViewController, I present a navigation controller like this:
UIStoryboard* storyboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
UINavigationController* nc = [storyboard instantiateViewControllerWithIdentifier:#"NAVIGATION_CONTROLLER_ID"];
[self presentViewController:nc animated:YES completion:nil];
Later, from somewhere within the view hierarchy of the UINavigationController, I need to return to MyMainViewController. How can I do this?
(Note: MyMainViewController is defined in a .XIB, and not in the storyboard where the UINavigationController and it's children are defined.)
It sounds like you have modally presented a NavController that you want to remove. Modally presented VC's can remove themselves.
Somewhere in your NavController add:
[self dismissViewControllerAnimated:YES completion:^{
NSLog(#"Dismissed nav controller modally");
}]
[self.navigationController popToViewController:[[self.navigationController viewControllers] objectAtIndex:2] animated:YES];
I gues you know the index of your view controller. If you simply want to return to the rootViewController you can do it like
[self.navigationController popToRootViewControllerAnimated:YES];
If you want to push new viewController to the navigation stack just do it like
MyMainViewController *mainController = [[MyMainViewController alloc] initWithNibName:#"MyMainViewController" bundle:nil];
[self.navigationController pushViewController:desController animated:YES];
Returning to the previous viewController would be
[self dismissViewControllerAnimated:YES completion:nil];

iOS switch back to background UIViewController

I'm looking for a way to present a modal view over my current UIViewController to basically show a UIActivityIndicator and force users to wait while data is being loaded.
in BaseViewController.m (base class of all my UIViewControllers):
// show loading view
-(void) showLoading
{
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
LoadingViewController *loading = [storyBoard instantiateViewControllerWithIdentifier:#"loadingView"];
loading.view.backgroundColor = [UIColor colorWithRed:0.9 green:0.9 blue:0.9 alpha:0.7];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentViewController:loading animated:NO completion:nil];
}
This works great, but how can I go back to the background view after the loading view should be done?
Need a stopLoading method to go back to the original view:
// stop loading
-(void) stopLoading
{
// code here
}
If I try to present a new view after I present the loading view like so:
UIStoryboard *storyBoard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
UIViewController *view = [storyBoard instantiateViewControllerWithIdentifier:#"loadingView"];
[self presentViewController:view animated:YES completion:nil];
The debugger gives Warning:
Attempt to present PropertyPickerViewController: 0x8af6010 on ViewController: 0x8ab23c0 which is already presenting LoadingViewController: 0x8acf530.
Try:
[self dismissViewControllerAnimated:YES completion:nil];
In fact, I'm not sure that it'a great idea to present new controller with animated gif.
The best option is (imo) show UIActivityIndicator + place a view on top on all other views to prevent user from clicking anything.
You must [self dismissViewControllerAnimated:YES completion:nil] first.
Check the Apple Documentation.

self.tabBarController dismissViewControllerAnimated doesn't work

I have a UITabBarController in my application.
I would like to present from one tab, another UIViewController.
So I wrote in ViewControllerA (which is a tab in the tabviewcontroller):
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
MyViewController *chooseTemplateController = [storyboard instantiateViewControllerWithIdentifier:#"myController"];
[self.tabBarController presentViewController:myController animated:NO completion:nil];
This shows MyViewController nicely.
However, how can I dismiss MyViewController?
I read in many questions that I need to call:
[self.tabBarController dismissViewControllerAnimated:NO completion:nil];
However - where do I call it from? I tried from MyViewController - but since it's not part of the UITabBar, self.tabBarController is null.
I initialize the UiTabBarController from storyboard and not from appDelegate and I would like to leave it that way.
Use the presented viewController's presentingViewController property
Objective-C
[self.presentingViewController dismissViewControllerAnimated:NO completion:nil];
Swift
presentingViewController?.dismissViewControllerAnimated(false, completion: nil)
You can also use this shorthand version (I don't recommend you do, but you will see it often)
Objective-C
[self dismissViewControllerAnimated:NO completion:nil];
Swift
dismissViewControllerAnimated(false, completion: nil)
see
Dismissing a Presented View Controller

Resources