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.
Related
I recently started a new project and after I successfully set up a login page, I came into a problem.
If I type in valid credentials in the text fields, my app should do the following:
if (user) {
[self.delegate loginViewControllerDidLogin:self];
...
The "if user" part means that everything was okay. After a few hours of searching I got to know that my [self.delegate loginViewControllerDidLogin:self]; should be defined in the AppDelegate.m file. Here I wrote the following code:
- (void)loginViewControllerDidLogin:(LoginViewController *)controller {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController * ViewController = [[UIViewController alloc] init];
[self.window addSubview:ViewController.view];
[self.window.rootViewController presentViewController:ViewController animated:YES completion:nil];
}
My problem is that I cannot define the ViewController on my story board, so I cannot connect the code with the ViewController itself.
So basically I would like the app to open a new ViewController after logging in.
On your storyboard select the view controller you want to display and fill out the "Storyboard ID":
Then instantiate it like this:
UIViewController * ViewController = [storyboard instantiateViewControllerWithIdentifier:#"YourVCStoryboardID"];
So I'm trying to figure out deeplinking. I have successfully gotten my app to recognize and run code I want it to depending on the path in the URL. Now when I present a View, it shows but can't get the back button or any way to dismiss it to work. Here's the code in my appdelegate:
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
BuyPremiumViewController *premiumViewController = [storyboard instantiateViewControllerWithIdentifier:#"BuyPremium"];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:premiumViewController];
[self.window makeKeyAndVisible];
[self.window.rootViewController presentViewController:navigationController animated:YES completion:NULL];
The reason I use a UINavigationController is to have the nav title and back button show in the presented view. Thing is, it is not working. Here is the code that runs when the back button is tapped in the presented view:
- (void)backButton {
NSLog(#"this ran"); //check if actually ran
[self.navigationController popToRootViewControllerAnimated:YES];
}
Being at it for a hours now, help?
Try to use this code:
- (void)backButton
{
NSLog(#"this ran"); //check if actually ran
[self.navigationController dismissViewControllerAnimated:YES completion:nil];
}
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];
I am a newbie in iOS development. I want to create 2 screens - (1) Login & on successful login (2) a Tab based view.
I started up with creating Login text boxes & button for Login in Storyboard. Now, how do I create other Tab view & show that new tab view on login btw click.
What would be the best approach for creating this type of screens ? In tutorials, I can find of creating Tabbed View as main or dynamic. Couldn't find the way I am looking for. FYI, I would like my app to be compatible with iOS 4 and above. I wish to plan and use resources accordingly. Sharing this, as in case it affects the approach to be selected.
Thanks
UPDATED AGAIN :
As shown/suggested in answer, I created a new project as TabbedView and added LoginViewController to the storyboard. In my LoginViewController under "Identity Inspector" - Identity - StoryboardID - gave name "loginViewController". Created Custom class for TabControl - MC_MainTabBarController.
My storyboard file name is Main_iPhone.storyboard.
In my AppDelagate file in didFinishLaunchingWithOptions method before return I added :
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
// MY First View of Tab
MC_ChatViewController *chatViewTab = [[MC_ChatViewController alloc] init];
// MY TabController class
MC_MainTabBarController *tabCtrler = [[MC_MainTabBarController alloc] init];
// Login view controller
LoginViewController *loginViewController = [storyboard instantiateViewControllerWithIdentifier:#"loginViewController"];
[loginViewController setModalPresentationStyle:UIModalPresentationFullScreen];
[tabCtrler presentViewController:loginViewController animated:NO completion:nil];
This should bring first Login screen and then the tabs, but it brings straight away tabs & no login screen. I feel I might be going wrong at 2 places - "Main_iPhone" OR I may have to set loginViewController as storyboard id somewhere else also. Where can't get it ?
UPDATE
Even after calling tabCtrler presentViewContorller ... also, still Login screen isn't showing up. Yet straight tabs are only visible. At Runtime, I see the following Warning :
Warning: Attempt to present <LoginViewController: 0x8ab4e80> on <MC_MainTabBarController: 0x8d4dc20> whose view is not in the window hierarchy!
UPDATE
With the below code in didFinishLaunchingWithOptions in AppDelegate I can get my login page.
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
MC_MainTabBarController *tabCtrler = [[MC_MainTabBarController alloc] init];
LoginViewController *loginViewController = [storyboard instantiateViewControllerWithIdentifier:#"loginViewController"];
[[[[UIApplication sharedApplication] delegate] window] setRootViewController:loginViewController];
Now, from Login -submitBtnClick, how do I get to my default Tab view ?? That should be handled in submitBtnClick in login class or her in AppDelegate only. How to achieve the same ?
Can please help to bring the login screen prior to tabs.
Thanks
Thanks BoranA & all friends,
I had to extend BoranA's answer for this to work, hence am sharing the solution that worked for me. AS BoranA instructed,
I created a new Project with tabbed template.
add LoginViewController screen to the Storyboard and gave it Id - "loginViewController".
Created class's for LoginViewController and MC_MainTabBarController for the main tab controller.
Added Storyboard Id to tab controller as "mainView".
In AppDelgate.h, added properties for loggedIn & tabController object
#property (nonatomic) bool isLoggedIn;
#property(nonatomic,strong)MC_MainTabBarController *tabBarController;
In AppDelegate.m :
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// 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"];
[self.window makeKeyAndVisible];
// Show the Login Screen
[self.window.rootViewController presentViewController:loginViewController animated:animated completion:nil];
}
-(void) logout {
// Remove data from singleton (where all my app data is stored)
//[AppData clearData];
// Reset view controller (this will quickly clear all the views)
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main_iPhone" bundle:nil];
// Create the tabBarController using Storyboard ID
self.tabBarController = (MC_MainTabBarController *)[storyboard instantiateViewControllerWithIdentifier:#"mainView"];
// Show the Tab Bar Controller
[self.window setRootViewController:self.tabBarController];
// Show login screen
[self showLoginScreen:NO];
}
Finally, in LoginViewController.m, when I am done with all process and have to show the main view, I call the following method :
-(void) loginWasSuccessful {
// Send Notification
[[NSNotificationCenter defaultCenter] postNotificationName:#"loginSuccessful" object:self];
// Dismiss Loginscreen
[self dismissViewControllerAnimated:YES completion:nil];
}
// LOGIN BTN CLICKED
- (IBAction)loginBtnClicked:(id)sender {
// Validate & Process Login
// If user is logged successfully, then only go to the main view.
if (self.processLogin)
[self loginWasSuccessful];
}
With this code, if isLoggedIn if AppDelegate is true, then it will straight away show the Tab controller and won't show Login screen. IF isLoggedIn is false, then first Login screen will come up and on successful login only tab controller will show up.
Hope this helps someone save time and get solution to their problem.
Thanks.
Create a project with tabbed application template.
Create your LoginViewController separately in your storyboard.
Add below code to your AppDelegate's didFinishLaunchingWithOptions method.
if (!isLoggedIn)
{
LoginViewController *loginViewController = [storyboard instantiateViewControllerWithIdentifier:#"loginViewController"];
[loginViewController setModalPresentationStyle:UIModalPresentationFullScreen];
[yourTabbarController presentViewController:loginViewController animated:NO completion:nil];
}
note: Dont't forget to specify storyboard id of your view as "loginViewController".
Solved:
once the user has logged in / signed up, use the following code to transition to the main storyboard...
UIWindow* window = [[UIApplication sharedApplication] keyWindow];
window.rootViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]] instantiateInitialViewController];
I have the following UINavigationController flow to handle logging in...the top segue after the tabbarcontroller goes to a uinavigationcontroller that is the root for a viewcontroller.
When the user is already logged in the "this segue works" is executed so that the user doesn't have to log in at the login screen. That works perfectly. The issue I run into is when the user has to login...the segue from the login/signup screen to the login screen works perfectly, but when I go from the login screen to the tabbar the following happens:
This really shouldn't happen because I have the following code in my viewcontroller.m (gotten to here is called)
- (void)viewDidLoad {
...
self.navigationItem.title = #"Messages";
self.navigationItem.hidesBackButton = YES;
NSLog(#"gotten to here");
...
}
Does anybody know why this is happening?
I like to keep my login flow separate from the normal app flow. This means that I don't link a segue from the login screen to the app, but I handle that in my AppDelegate:
if ([MyUserHandler sharedHelper].isAuthenticated) {
[self presentMainInterface];
} else {
[self presentWelcomeInterface];
}
Where the first method does this:
- (void)presentMainInterface
{
self.window.rootViewController = [[UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]] instantiateInitialViewController];
}
and the other presents the login screen:
- (void)presentWelcomeInterface
{
UIViewController* rootController = [[UIStoryboard storyboardWithName:#"Main" bundle:[NSBundle mainBundle]] instantiateViewControllerWithIdentifier:#"loginScreen"];
UINavigationController* navigation = [[UINavigationController alloc] initWithRootViewController:rootController];
self.window.rootViewController = navigation;
}
This way the login screen is loaded only when the user is not authenticated.
Make a custom class (sub class) of UITabBarControler and assign that custom class for your tabbarcontroller in storyboard. Then In viewDidLoad of custom tabbarcontroller add your code
self.navigationItem.hidesBackButton = YES;
It will work fine.