In my app i have a login screen which i present modally on startup. After a successful login, the user gets redirected to a UITabBarController which has five UINavigationController (for the tabs).
On one tab, i have a button "logout", so that the user gets redirected back to the login screen.
That´s working fine.
But what i want to do is to load the UITabBarController every time the user logs in. That means, that the UITabBarController should NOT be reused. For now, the content in the tabs (i load data from web) stays the same, also when a new login has been done.
How can i release/pop/nil the UITabBarController with it´s UINavigationcontrollers?
What i have tried so far:
Thats the point where i push the user back to the login screen when he presses the "logout" button:
[self.navigationController presentModalViewController:navigContrLogin animated:YES];
[[self navigationController] popToRootViewControllerAnimated:YES]; --> NOT WORKING
[self.navigationController popViewControllerAnimated:NO]; --> NOT WORKING
[self.tabBarController release]; ---> NOT WORKING
Can anybody help me please?
EDIT:
That´s how i add the UITabBarController. I do this when the user clicks the Login Button:
[self.navigationController dismissModalViewControllerAnimated:NO];
[self.navigationController setNavigationBarHidden:YES];
[self.navigationController pushViewController:tabBarController animated:NO];
[self.navigationController removeFromParentViewController];
EDIT2: I solved it. What i´m doing is when the user clicks the logout button, i call the navigation controller from the app delegate and use it to push the login viewcontroller.
MyAppDelegate *del = (MyAppDelegate*)[UIApplication sharedApplication].delegate;
[del.navControllerLogin pushViewController:loginController animated:YES];
Have you tried to remove it from the superview and then release it? And then add new ViewControllers?
for (UIView *view in self.window.subviews){
if (view == tabBarController.view) {
[view removeFromSuperview];
}
}
[tabBarController release];
UITabBarController *newTabBarController = [[UITabBarController alloc] init];
newTabBarController.viewControllers = nil; //ADD NEW VIEWCONTROLLERS
[self.window addSubview:newTabBarController.view];
i wouldn't do it with this way. Because managing (release/nil) a parent view from its subview is not a good practice.
init and show tabbar controller after app launch.
if user is not logged on, present loginviewcontroller. if already logged on no need.
after successfull login post a notification and capture it required places.
if user taps on logout, clear user credentials, user related data and present loginviewcontroller again.
I'd add and remove both the modal view controller and tabbarcontroller from the appDelegate.
[myAppDelegate addLoginViewController];
[myAppDelegate removeLoginViewController];
[myAppDelegate addTabBarController];
[myAppDelegate removeTabBarController];
Related
I have an application that pulls up a login page when it first starts. This login page goes over the application and does not let anyone through until they've logged in. I also have a settings tab on my main application that needs to lead back to this login screen. Right now it displays the login screen with the tab bar over it. Is there a way to get the login view over the tab bar?
I've done something similar by having views transitioning in over the top of my tab bar. I used yourView.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; with a 'close' button to let users return to the tab bar screen. I've not done this so it automatically comes in on app fire-up but instead call the view from a button on the screen separate to the tab bar controls. However, I'm sure you'll be able to utilise this somehow to do what you want.
In fact I've actually used this way of calling up views all over my app, each time it covers the tababr and you have to 'close' it to get back to main tabbed navigation you came from.
Try setting below in your viewDidLoad of login screen:
self.tabBarController.hidesBottomBarWhenPushed = YES;
You can do this by using a subclass of UITabBarController, which then performs various checks in viewDidAppear:. The login view is modally presented, as #Maxwell suggested.
// a subclass of UITabBarController
- (void) viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self firstLoadChecks];
}
- (void) firstLoadChecks
{
if (!self.hasLogin) {
id login = [[[LoginViewController alloc] initWithDelegate:self autorelease];
id nav = [[[UINavigationController alloc] initWithRootViewController:login] autorelease];
nav.modalPresentationStyle = UIModalPresentationStyleFormSheet;
nav.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:nav animated:YES];
}
}
// from LoginViewControllerDelegate
- (void) didLogin
{
self.hasLogin = YES;
[self dismissModalViewControllerAnimated:YES];
}
// my LoginViewController can be closed without a login
- (void) dismissModalViewControllerAnimated:(BOOL) animated
{
[super dismissModalViewControllerAnimated:animated];
[self firstLoadChecks];
}
I have a UIViewController called LoginViewController. The UIViewController has two UITextField, username and password. This is displayed as a modalViewController when the first time the app is launched and there isn't any credentials in the keychain. When the user clicks on the login button the keyboard that is presented is dismissed. The code is:
- (IBAction) loginClick: (UIButton *) sender
{
if ([username isFirstResponder]){
[username resignFirstResponder];
}
if ([password isFirstResponder]){
[password resignFirstResponder];
}
[RKObjectManager sharedManager].client.username = username.text;
[RKObjectManager sharedManager].client.password = password.text;
[progressLock lock];
[progressLock unlockWithCondition:0];
[HUD showWhileExecuting:#selector(myTask) onTarget:self withObject:nil animated:YES];
[[RKObjectManager sharedManager] loadObjectsAtResourcePath:#"/account/verify.json" objectClass:[Login class] delegate: self];
}
Now inside the app there is an options button. When this is click it will present a modalViewController which has a logout button in it. Clicking on this logout button will present the LoginViewController again. The code is:
- (IBAction) logout:(id)sender
{
NSUserDefaults *standardDefaults = [NSUserDefaults standardUserDefaults];
NSString * username = [standardDefaults stringForKey:#"kApplicationUserNameKey"];
NSError * error = nil;
[standardDefaults removeObjectForKey:#"kApplicationUserNameKey"];
[SFHFKeychainUtils deleteItemForUsername:username andServiceName:#"convore" error:&error];
LoginViewController* lvc = [[LoginViewController alloc] init];
lvc.delegate = self;
[self.mgvc.groups removeAllObjects];
[self.mgvc.table reloadData];
Topic * topic = [Topic object];
topic.tid = [NSNumber numberWithInt:-2];
self.mgvc.detailViewController.topic = topic;
self.mgvc.detailViewController.detailItem = topic.tid;
[self presentModalViewController:lvc animated:YES];
[lvc release];
}
What's weird is that I can't seem to dismiss the keyboard when I click on the login button this time. Why is this? Is it because as of now I am displaying the LoginViewController from a modalviewcontroller? How do I solve this weird issue?
I don't know whether the fact that you can't dismiss the keyboard is due to presenting the login in a modal view, nor do I see anything evidently wrong with your code.
I would suggest you to change your flow and make:
the logout button dismiss your first modal view and,
your login view be displayed as a normal view, once the modal view disappears.
Explicitly, you can do 2 either by one of several means:
trying and pushing the login view controller on your navigation controller (if you have one);
selecting it in a tab bar controller (if you use one);
your modal view is shown above a view; when the modal is dismissed, that view appears again, and so the viewWillAppear selector of its view controller is called; that's the place where you can check if you are logged in or out and show the login, if necessary; if you don't know how to detect if your are in or out, you can always set a flag in the view controller when you dismiss the logout modal view.
(after reading your comment: modal view is not full screen, so viewWillAppear is not called: you can either send viewWillAppear yourself, or send a different, custom message to your superordinate view controller so that it knows that the login view should be displayed (and possibly refresh the view).
EDIT: try something like this (this requires that you call your own selector, not viewWillAppear):
[baseNonModalViewController performSelector:#selector(yourSelector) withObject:nil afterDelay:0.0];
Executing performSelector with a 0.0 delay, has only the effect of scheduling yourSelector for execution on the main loop. This way, first the modal will be completely dismissed, then the login view will be displayed.
I have the following code in application didFinishLaunchingWithOptions where I want to present a modal view controller for user login.
LoginViewController_iPhone *loginViewController=[[LoginViewController_iPhone alloc]initWithNibName:#"LoginViewController_iPhone" bundle:nil];
UINavigationController *loginNavigationController=[[UINavigationController alloc]initWithRootViewController:loginViewController];
loginNavigationController.modalPresentationStyle=UIModalPresentationFullScreen;
[self.window.rootViewController presentModalViewController:loginNavigationController animated:NO];
[loginViewController release];
[loginNavigationController release];
However, all I get is a blank white screen. If I substitute the following
self.window.rootViewController=loginNavigationController;
the login screen displays correctly. There is no other view controller assigned to the rootViewController property as the app is just starting. Do I need another view controller assigned to get this to work?
Yes. you need to assign something to the window's rootViewController property in order to call its method presentModalViewController.
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:LoginViewController];
navController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:navController animated:NO];
You can set this up in the viewDidLoad of the view that would load up first as soon as the app starts. So, as soon as login is successful, you can pop it off, and you will have the loaded view ready.
i have a problem in my app. in an tabbarcontroller i have a login view where i can enter a website. if the login data is correct the view switches to another view. works fine.
now my problem is, when i switch the tab and enter the login view tag again and try to login again, the view does not load.
Whats here the problem? should i dismissmodalviewcontroller when the view is unload or something else???
thanks for help,
brush51
EDIT1:
hi robin, in my login view is an button which calls a webview whit this code:
ShopWebViewController *shopWVC = [[ShopWebViewController alloc] initWithNibName:#"ShopWebViewController" bundle:nil];
shopWVC = [[ShopWebViewController alloc] initWithNibName:#"ShopWebViewController" bundle:nil];
shopWVC.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[logView presentModalViewController:shopWVC animated:YES];
And now when i exit the tabbar item where this logview is and enter it again, then the first view appears and the login/presentmodalviewcontroller doesnt work again.
cause of this i think that i may have to dismissmodalviewcontroller but dont know if this is right or not.
When you hit the login button:
ShopWebViewController *shopWVC = [[ShopWebViewController alloc] initWithNibName:#"ShopWebViewController" bundle:nil];
shopWVC.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:shopWVC animated:YES];
[shopWVC release];
Then in your view controller that has just been presented modally, somewhere in your code (perhaps when login is successful?) you need to dismiss it with
[[self parentViewController] dismissModalViewControllerAnimated:YES];
i have a 3 tabbar in my app. in my Appdelegate i have a reference to loginview where i am popingup loginview if user is not logged in.here is method.
- (void)LoginView
{
loginView = [[[LoginViewController alloc] initWithNibName:#"LoginView" bundle:nil] autorelease];
UINavigationController* nav = (UINavigationController*)[tabBarController.viewControllers objectAtIndex:0];
loginView.navC = nav; [nav presentModalViewController:loginView animated:YES];
}
3rd tabbar is a settings view and i have a signout button there.
at first time i can see correct user name,but as soon as i click sign out i am calling same method shown above using app delegate. logview gets popedup correctly and if i signin as different user it still show previous user name (because 3rd tabbar view is already loaded)
so my question is
1)which is the best place to put loginview
2)how do i reset the app w/o restarting it after signout
i hope my question is clear. or i am willing to give more details.
thanks.
Update:
basically i want to unload all view on signout and start from the beginning.
Better method would be to create a public changeLoginName: method on your settings controller, and call that method from the login view when the user is logged in. You can access that view through your tab bar, if you don't keep pointers to it anywhere else.
something which worked for me, and i hope this is proper way to doing.here is what i did.
NSArray *vc= tabBarController.viewControllers;
for (int i = 0; i < [vc count]; i++) {
UINavigationController *nc = [vc objectAtIndex:i];
if (nc == tabBarController.selectedViewController) {
continue;
}
[nc popToRootViewControllerAnimated:NO];
}
i hope this unloads all the view from memory and force them to load again when tabbar is getting switched.let me know if this is not good way.