open rootViewController with button - ios

I recently work on a tutorial for my app. I created the tutorial with this Tutorial:
http://www.appcoda.com/uipageviewcontroller-tutorial-intro/
I created a "button" which brings the user back to the rootViewController, in this case the TabBarController. Problem is: with this tutorial I made a extra storyboard for the tutorial. So how can I go back to the original rootViewController(TabBarController) with the button?
Code:
- (IBAction)start:(id)sender {
UIViewController* backToRootViewController = [[UIViewController alloc] initWithNibName:#"TabBarController" bundle:[NSBundle mainBundle]];
[self.view addSubview:backToRootViewController.view];
}
This does not work, too
- (IBAction)start:(id)sender {
[self.navigationController popToRootViewControllerAnimated:YES];
}
EDIT
To open the tutorial at the first start:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
BOOL isAccepted = [standardUserDefaults boolForKey:#"iHaveAcceptedTheTerms"];
if (!isAccepted) {
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.viewController = [[APPViewController alloc] initWithNibName:#"APPViewController" bundle:nil];
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
}
APPViewController is the Tutorial
EDIT
After the help of johnnelm9r the current code is this:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"main" bundle: nil];
IntroViewController *introViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"IntroViewController"];
BOOL isAccepted = [standardUserDefaults boolForKey:#"iHaveAcceptedTheTerms"];
if (!isAccepted) {
[self.window.rootViewController presentViewController:introViewController animated:NO completion:nil];
}
But now, sadly, the app crashed and the error is:
Application tried to present a nil modal view controller on target <UITabBarController: 0x175409d0>.'
and also a warning: Incompatible pointer type assigning to 'ViewController' from 'UIViewController' in AppDelegate

*****UPDATE****
I uploaded a sample project to demonstrate what I mean. You can find it here: github link
Good luck!
**** EDIT
After talking with you more I'd suggest trying to use something similar to this code in your viewDidAppear method of whatever view controller runs the first tab of your tabbarcontroller (obviously you want your own class name where I have IntroViewController):
BOOL didShowIntro = [[NSUserDefaults standardUserDefaults] boolForKey:#"showIntro"];
IntroViewController *introViewController = [self.storyboard instantiateViewControllerWithIdentifier:#"IntroViewController"];
if (didShowIntro)
{
[self presentViewController:introViewController animated:NO completion:nil];
}
and then just pop the presented controller from your button in the tutorial like so:
[self dismissViewControllerAnimated:NO completion:nil];
Just remember to set your user defaults to no when you press the button in your tutorial view controller. And make sure you are going from tabbarcontroller to navigationcontroller as a relationship segue and then to the view controller you want to show after the tutorial as a root. Just to be clear: there should be no connection to the tutorial view controller on your storyboard.
Just to be extra clear: your storyboard should have the navbarcontroller as your initial view controller connected to a navigationcontroller connected to a view controller and another view controller not connected to anything. :) And make sure you delete the code in the delegate.

To go to rootViewController
[self.navigationController popToRootViewControllerAnimated:YES];

Related

How to return to root ViewController, if the current is deeply nested?

I have a problem that my iOS app has several ViewControllers.
For example: ViewControllers named like A, B, C. A jumped to B with pushViewController, B jumped to C with presentViewController , C jumped to D with presentViewController and so on.
If the current ViewController is Z or some other ViewController, how can I jump back to A directly?
Try Below code. It will work for all cases :
for (UIViewController *controller in self.navigationController.viewControllers)
{
if ([controller isKindOfClass:[nameOfYourViewControllerYouWantToNavigate class]])
{
if(controller.isBeingPresented)
[controller.presentingViewController dismissViewControllerAnimated:YES completion:NULL];
else
[self.navigationController popToViewController:controller animated:YES];
break;
}
}
[[self navigationController] popToRootViewControllerAnimated:YES];
It will pop your viewcontroller to Root controller.
For the view controllers show by pushViewController, you can get rootViewController via [self.navigationController.viewControllers objectAtIndex:0]
Others shown by presentViewController, you can get parent view controller via self.presentingViewController
Whatever you want to go back to A ViewController from any other view controller, first you have to set that as RootViewController. If you use XIB you must set as root in app delegate didFinishLaunchWithOptions method. If you use storyboard you should set NavigationController in storyboard and set AViewController as ROOT using control+drag(mouse).
I work in a project which has lot of view controllers. It has pushViewController and PresentViewControllers also I set A asRootViewController. So I can return from any view controller to RootViewController.
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
self.window = [[UIWindow alloc]initWithFrame:[[UIScreen mainScreen] bounds]];
AViewController *aVC = [[AViewController alloc]initWithNibName:#“AViewController" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:aVC];
self.window.rootViewController = aVC;
[navController setNavigationBarHidden:YES];
self.window.backgroundColor = [UIColor clearColor];
[self.window makeKeyAndVisible];
return YES;
}
For going to AViewController from any other view controller
- (IBAction)actionGoBack:(id)sender
{
[self.navigationController popToRootViewControllerAnimated:YES];
}

Loading new Storyboard and UIButton inactive

I added a new UIViewController to get a log in issue fixed and now the button in the NavigationBar on the next scene are inactive. Here is the code I used to load the new StoryBoard:
-(void)newSotrybooard{
UIStoryboard *settingsStoryboard = [UIStoryboard storyboardWithName:#"LogedIn" bundle:nil];
UIViewController *initialSettingsVC = [settingsStoryboard instantiateInitialViewController];
initialSettingsVC.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:initialSettingsVC animated:YES completion:NULL];
}
I added the new storyboard after I couldn't get the NavigationBar to show up and push without and error on the main storyboard. This is the only code that has changed. The Navigation Controller does not have a class associated with it and neither does the TableView to follow. I can also not scroll the Table view. Thank you for your help!
Update:
I updated the code above and
The error I receive is:
Warning: Attempt to present <UINavigationController: 0x109fa0ce0> on <PrivateViewController: 0x109f6ef80> whose view is not in the window hierarchy!
Based on the information you have provided, I surmise that the following could be helpful -
Yes, you have used instantiateViewControllerWithIdentifier.
But, remember it instantiates and returns the view controller with
the specified identifier. You're missing that.
Provide the same name to your new Storyboard in your code and
File Inspector (like you named it LogedIn above) and it
should be set in the Main Interface (Target >> General >> Main
Interface).
See rootViewController? The rootViewController
for the window needs to be assigned (either via Storyboard or
programmatically). Please check. I have added a UINavigationController in my example below -
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"StoryboardName" bundle:nil];
ViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"StoryboardName"];
vc.title = #"Is this title visible?";
UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc];
self.window.rootViewController = nav;
return YES;
}
For the ViewController.m
-(void) goToSettings {
UIStoryboard *settingsStoryboard = [UIStoryboard storyboardWithName:#"SettingsStoryboard" bundle:nil];
UIViewController *initialSettingsVC = [settingsStoryboard instantiateInitialViewController];
initialSettingsVC.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:initialSettingsVC animated:YES completion:NULL];
}

Presenting Login as modal iOS?

I have an app that has a login nav controller and a tab bar controller. I have set my tab bar controller to the root controller however I want the login navigation controller to display as a modal so that I can dismiss it when they're logged in and not show it at all if they are. It is reading the right line but failing to present the landingviewcontroller. When I run the app it jumps straight to the TabBarController.
My code is as follows:
I have a method which checks if you are logged in in my app delegate which is where I am telling it to present the landing view controller (login). I know from stepping through that it is correctly determining that I'm not logged in and going to this line of code on running:
[self.window.rootViewController presentViewController:landingVC animated:YES completion:nil];
The full app delegate:
#import "GFAppDelegate.h"
#import "GFCredentialStore.h"
#implementation GFAppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:[NSBundle mainBundle]];
UIViewController *tabBarController = [storyboard instantiateInitialViewController];
UIViewController *landingVC = [storyboard instantiateViewControllerWithIdentifier:#"LandingViewController"];
GFCredentialStore *store = [[GFCredentialStore alloc] init];
if (store.isLoggedIn) {
self.window.rootViewController = tabBarController;
} else {
[self.window.rootViewController presentViewController:landingVC animated:YES completion:nil];
}
// Set root view controller and make windows visible
[self.window makeKeyAndVisible];
return YES;
}
I've tried to make this clear, but understand it's probably confusing as poorly written. Thanks for any help.
What you need to do is to always set rootViewController to tabBarController, but if user is not logged call presentViewController from it. Something like it:
self.window.rootViewController = tabBarController;
[self.window makeKeyAndVisible];
if (!store.isLoggedIn) {
[tabBarController presentViewController:landingVC animated:YES completion:nil];
}
Try this:
self.window.rootViewController = tabBarController;
[self.window makeKeyAndVisible];
if (store.isLoggedIn==false) {
[tabBarController presentViewController:landingVC animated:YES completion:nil];
}
Your problem is that when tries to present view controller from self.window.rootViewController is does not exist so rootViewController == nil.
I suggest you to not present it as modal (since you don't have controller to present from), but to set login view controller as root.
self.window.rootViewController = landingVC;
But if your intent was to present login above tab bar see answers suggested before mine.

How can I load a view "properly" iOS

My app consists of a navigation controller and view controllers. Some parts of my UI is done on storyboard and some are initiated from code (in viewDidLoad). My goal is to load childViewController X (consists of a back button, nag bar, label and table) when the app is launched from a push notification "properly" through this method in appDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
This might be a simple question to you guys but I've asked several questions the pass few days (you can look at my questions history). After trying several methods, my app either:
crashes
loads without navigation bar
loads with navigation bar but no label (back button does not work)
loads with navigation bar but with black screen underneath
Only the tableView is dragged onto storyboard. The navigation bar is inferred but I have code that dictates its back button and title. The rest is all done through code in the .m file.
I know people have asked this question before but none of the methods worked. How can I load this childViewController properly through a push notification?
EDIT/UPDATE:
My code so far:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSDictionary *dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if (dictionary != nil)
{
UIStoryboard *mainstoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController* firstVC = [mainstoryboard instantiateViewControllerWithIdentifier:#"NotificationsViewController"];
[self.window.rootViewController addChildViewController:firstVC];
[(UINavigationController *)self.window.rootViewController pushViewController:firstVC animated:NO];
self.window.rootViewController.childViewControllers);
}}
Error Code:
'-[SWRevealViewController pushViewController:animated:]: unrecognized selector sent to instance 0x14575f20'
SWRevealViewController is my library for my sidebar menu view controller.
UPDATE2:
I've also tried this method:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *initViewController = [storyboard instantiateViewControllerWithIdentifier:#"NotificationsViewController"];
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.rootViewController = initViewController;
[self.window makeKeyAndVisible];
This loads the correct viewController but without a navigation bar.
Try this:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSDictionary *dictionary = [launchOptions objectForKey:UIApplicationLaunchOptionsRemoteNotificationKey];
if(dictionary != nil) {
UIStoryboard *mainstoryboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *firstVC = [mainstoryboard instantiateViewControllerWithIdentifier:#"NotificationsViewController"];
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
// Navigation already created
if(navigationController) {
[navigationController pushViewController:firstVC animated:NO];
// Navigation not created
} else {
UINavigationViewController *navigationController = [[UINavigationViewController alloc] initWithRootController:firstVC];
[self.window setRootViewController:firstVC];
[self.window makeKeyAndVisible];
}
}
return YES;
}
You had some problem in your code:
You need to have a UINavigationController in order to have a navigation bar and manage the push/pop actions, so your window root controller should be a UINavigationController.
If you need to initialize a UINavigationController the best and simple way is to initialize it with a root controller directly, so leave the push/pop for user actions: an application has always a root controller, so why don't you create it immediately?
The "addChildController" is another thing: it is used to create custom container controller, it means that you have to implement all the business logic manually. I suggest you to use it only if you are experienced enough, since it could be difficult - Cocoa has enough components to leave it for a small set of applications.
You are using a third part controller, the "SWRevealViewController". They should have an example project, you can try to "copy" it and them customize it for your own purpose.
Let me know if your code works well, otherwise post the new error and I'll try to help you

iOS How to go to Previous to Previous View

I have a situation where I want to go from Previous to Previous view.
A MainView calls modal CWViewC calls modal CRViewC & that calls modal CRDViewC - on a action event in CRDViewC I need to return to CWViewC & update a component of it.
I want to use navigationController in my app, but am not able to set it, hence right now am not using it at all. I also am scared to play with Segue's also thinking that it might affect the compatibility of the app :(. I searched on net for similar situation but can't find a solution.
I could think of sending any sort of notification to CWViewc from CRDViewC. But again how to implement it in both respective classes & how to get rid of (I mean close) CRViewC then.
So please suggest and guide me for the same to solve the problem.
Any help is highly appreciated. Thanks.
EDIT :
My req was I have to call LoginVC prior & my main scrn is MAinTabVC. So I have made my app as TabbedTemplate & I call my LoginVC from AppDelgate & on when logged in successfully, from AppDelegate my MainTabVC comes up. This is how I call my login :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// Get the StartupData properties from device
MC_Utility *utility = [[MC_Utility alloc] init];
self.theAppDataObject.startupData = [utility retrieveLocalData];
NSLog(#"READ Loigin On Launch - %#", self.theAppDataObject.startupData.loginOnLaunch);
utility = nil;
// Show Login view if not logged On
if (!self.isLoggedIn) {
[self showLoginScreen:NO];
}
return YES;
}
-(void) showLoginScreen:(BOOL)animated {
// Get login screen from storyboard and present it
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
LoginViewController *loginViewController = [storyboard instantiateViewControllerWithIdentifier:#"loginViewController"];
// Show Login
if (theAppDataObject.startupData.loginOnLaunch.boolValue == true) {
NSString *email = #"dylan#antila.co";
NSString *pswd = #"t4Wzpg4OQ5q8ZNVDPPo7wg==";
[loginViewController startLoginProcess:email :pswd];
} else {
[self.window makeKeyAndVisible];
[self.window.rootViewController presentViewController:loginViewController animated:animated completion:nil];
}
}
Other all views that I normally show using such code :
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
MC_ChatWindowViewController *chatWindVC = [storyboard instantiateViewControllerWithIdentifier:#"chatWindowVC"];
[chatWindVC setModalPresentationStyle:UIModalPresentationFullScreen];
[self presentViewController:chatWindVC animated:YES completion:nil];
In my AppDelegate, I had tried to call mainTabVC, but wasn't successful. So stuck to original code. Tried several ways thru few tutorials also, but couldn't do it. I am a newbie in iOS development & am not finding comfortable yet to work with navControllers.
I have embedded NavController in LoginVC thru storyboard.
CODE Added in MAinTAB .m
#implementation MC_MainTabBarController
bool isLogged = false;
-(void) showLoginScreen:(BOOL)animated {
NSLog(#"Calling Login from MainTab");
// Get login screen from storyboard and present it
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
LoginViewController *loginViewController = [storyboard instantiateViewControllerWithIdentifier:#"loginViewController"];
[loginViewController setModalPresentationStyle:UIModalPresentationFullScreen ];
[self presentViewController:loginViewController animated:YES completion:nil];
/* AUTO LOGIN
// Show Login
if (theAppDataObject.startupData.loginOnLaunch.boolValue == true) {
NSString *email = #"dylan#antila.co";
NSString *pswd = #"t4Wzpg4OQ5q8ZNVDPPo7wg==";
[loginViewController startLoginProcess:email :pswd];
} else {
[self.window makeKeyAndVisible];
[self.window.rootViewController presentViewController:loginViewController animated:animated completion:nil];
} */
}
-(void)viewWillAppear:(BOOL)animated {
if (isLogged == false) {
[self showLoginScreen:YES];
}
}
As you mentioned segues, can I safely assume you're using storyboards? If so, get your first view controller (the one with MainView) in the storyboard file, go to the Product menu in the menu bar and select Embed In>Navigation Controller,as shown in this screenshot:
Then, change those segues between your view controllers to be Push rather than modal, so the one from mainView to the CWViewC will be Push, then the one from CWViewC to CRViewC will be Push and so on.
The views won't be modal, but this is a much more natural way of progressing through a stack of views.

Resources