Login/Logout with UITabBarController? - objective-c

I'm having issues with the following.
Atm i have a LoginView that sends the user to a tabbarcontroller.After verification the user is sent to the tabbarcontroller with the following code:
-(void)userSuccessfullyLoggedIn{
[self.window setRootViewController:myTabBarController];
[myTabBarController setSelectedIndex:0];
[self.window makeKeyAndVisible];
}
After this, the user is successfully sent to the first view in the tabbar.
The 5th item on the tab-bar holds an empty view to "log out" the user from the tabbarcontroller back to the LoginView.
// The following code intercepts the popup that confirms the "log out" dialog.
-(void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex{
// index 0 is the YesButton that is supposed to "log out" the user.
if (buttonIndex == 0)
{
myAppDelegate *appDelegate = [[UIApplication sharedApplication] delegate];
[appDelegate userLogsOut];
}
else{
NSLog(#"The user chose not to logout. Passing the user to the first tab");
[[self myTabBarController] setSelectedIndex:0];
}
}
The [delegate userLogsOut] code is as follows:
-(void)userLogsOut{
[self.window setRootViewController:myLoginViewController]
[self.window makeKeyAndVisible];
}
And now to describe the problem.
It works just as i want it, except for when the user logs back in again and is supposed to land on the first tab holding the first view, the popup dialog from the empty logoutView just appears out of nowhere.
The first view is visible in the background, and if selected NOT to log out, the dialog disappears, if the user is selecting YES at this point, the user gets logged out again.
Thanks for reading, and any tips and/or pointers will be highly appreciated. Thanks in advance.

Sorry I cannot test it now, but I think when you log in for the second time, the Logout tab (fifth tab) is still active when [self.window setRootViewController:myTabBarController]; was called, before you selected the first tab with [myTabBarController setSelectedIndex:0];. You could try switching the first and second lines in - (void)userSuccessfullyLoggedIn like:
-(void)userSuccessfullyLoggedIn{
[myTabBarController setSelectedIndex:0];
[self.window setRootViewController:myTabBarController];
[self.window makeKeyAndVisible];
}

Related

ModalViewController Without Dimming / Disabling current viewcontroller

I am displaying aNavController as a modalViewController in a specific frame CGRectMake(40,50, 400, 500). Which is working fine. Now I have a button in self (viewcontroller on which modalViewController is presented), on pressing that button I need to display some message on aNavController. But problem is when I am presenting a modalViewController. Whole screen area got dimmed/disabled. So, not able to touch/click that button in self.
Here is my code to present a view controller. I thought, I am missing something here. Please Help. Thanks in advance.
aNavController.modalPresentationStyle = UIModalPresentationFormSheet;
anavController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:aNavController animated:YES];
aNavController.view.superview.frame = CGRectMake(40,50, 400, 500);
presentModalViewController create a modal dialog. When modal view controller is up, users can't do any thing on parent view until the the modal view is dismissed.
The problem is you're instantiating a UIAlertView at the same time as the presentModalViewController call your modal view in UIAlertView's delegate method clickedButtonAtIndex.
Like so:
- (IBAction)clickedMyButton:(id)sender
{
UIAlertView *alertView = [[UIAlertView alloc]
initWithTitle: #"Title"
message: #"Message"
delegate:self
cancelButtonTitle:#"Close Button"
otherButtonTitles:#"Modal Button", #"Some Other Button", nil];
[alertView show];
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
NSLog(#"User Selected Cancel");
}
else if (buttonIndex == 1) {
NSLog(#"Modal Button Clicked");
aNavController.modalPresentationStyle = UIModalPresentationFormSheet;
anavController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
[self presentModalViewController:aNavController animated:YES];
aNavController.view.superview.frame = CGRectMake(40,50, 400, 500);
}else {
NSLog(#"Some Other Button Clicked");
}
}
Or, if you wish for your UIAlertView to show on top of your navigation controller, ignore the above and simply wait to call your alert until the navigation controllers - (void)viewDidAppear:(BOOL)animated method.
In addition, I recommend you change your frame to stay within the bounds of the screen unless absolutely necessary. ex: CGRectMake(40, 50, 320, 480);
Finally, I am able to do workaround the things which work same way as a UIModalPresentationFormSheet.
I added the aNavController as a subview to the [[UIApplication sharedApplication] keyWindow] and which solves my all the problems.
Thank you all for your comments.

How can I show UIActionSheet to confirm moving back in Navigation View

Using Xcode I have View A that navigates to View B.
Upon pressing the Back UIBarButtonItem, I'm trying present the user with a UIActionSheet to confirm navigation to move back to View A.
What do I need to do in code to stop the view from navigating back and then (depending on user input) move back or stay on the current screen?
add a backbutton programmatically.
eg.
UIButton *backBtn= [[UIButton alloc] initWithFrame:CGRectMake(0,0,54,30)];
[backBtn addTarget:self action:#selector(backButtonPressed:)forControlEvents:UIControlEventTouchUpInside];
UIBarButtonItem *backBarButton = [[UIBarButtonItem alloc] initWithCustomView:backBtn];
[backBtn release];
[[self navigationItem] setLeftBarButtonItem:backBarButton];
[backBarButton release];
//backButtonPressed is the selector for backBtn
Then present you ActionSheet from that selector and based on user either navigate to previous viewController or dont.
To navigate to previous page, use popViewMethod.
`
You should not present UIActionSheet for every other action.It would be better to use UIAlertView for this purpose. According to Apple UIActionsheet Guidelines :-
Provide alternate ways a task can be completed. An action sheet allows you to provide a range of choices that make sense in the context of the current task, without giving these choices a permanent place in the user interface.
Get confirmation before completing a potentially dangerous task. An action sheet prompts users to think about the potentially dangerous effects of the step they’re about to take and gives them some alternatives. This type of communication is particularly important on iOS-based devices because sometimes users tap controls without meaning to.
for UIAlertView :-
UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:#"Alert View"
message:#"Do You want to go back to previous screen?"
delegate:self
cancelButtonTitle:#"NO"
otherButtonTitles:#"YES",nil];
[alertView show];
[alertView release];
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) {
NSLog(#"THE 'NO' BUTTON WAS PRESSED");
}
if (buttonIndex == 1) {
NSLog(#"THE 'YES' BUTTON WAS PRESSED");
}
}
Implement this on action of back button of UINavigationController.According to the buttons pressed "YES" or "NO" , you can allow navigation.Also conform to UIAlerrtVIewDelegate protocol.

Remove all settings from viewcontroller when dismissed

I got multiple viewcontrollers in my project. The first viewcontroller is called when the application starts and it presents a login screen. When the credentials are correct and the user logs in, the modalview is dismissed. and another viewcontroller is instantiated like this:
[self dismissModalViewControllerAnimated:NO];
Form *formcontroller = [[Form alloc] init];
[self presentModalViewController:formcontroller animated:YES];
When my other viewcontroller is presented the old one disappears. On the top of my secondviewcontroller i got an logout button, wich does exactly the same, so it dismisses the current viewcontroller and calls another like this:
-(IBAction)logOut:(id)sender{
[self dissmissModalViewControllerAnimated:NO];
}
And in my viewdiddisappear:
-(void)viewDidDisappear:(BOOL)animated{
Postform3ViewController *logincontroller = [[Postform3ViewController alloc] init];
[self presentModalViewController:logincontroller animated:YES];
}
The problem is:
When i push the logout button, and i return back to the logincontroller. The Credentials are still filled in. So my conclusion is that the first viewcontroller stays in memory. What am i doing wrong?
Edit:
I did find my own solution. I was profiling my application, and couldn't find any memory leaks. So i decided everything is released. Then i thought that i was able to set everything to empty myself. I did that in the viewDidAppear method like this:
-(void)viewDidAppear:(BOOL)animated {
gebruikersnaam.text = #"";
wachtwoord.text = #"";
[self.activeTextField resignFirstResponder];
[super viewDidAppear:animated];
}
Well first of all when you are using presentModalViewController and pushViewController the VC is retained so you should always release it after you have presented or pushed it.
Secondly in the third block of code it looks like you are creating a logincontroller but presenting a formcontroller. Perhaps you want to be presenting the VC you had just created:
[self presentModalViewController:logincontroller animated:animated];
Edit 0: For your code, in the first block, release like this:
Form *formcontroller = [[Form alloc] init];
[self presentModalViewController:formcontroller animated:YES];
...
[self dismissModalViewController:formcontroller animated:YES];
[formcontroller release];

Don't allow user interaction when activity indicator view is visible

I have a view which contains two views. One of those views contains two buttons and some text labels. The other one, with alpha set to 0.25, has an UIActivityIndicatorView to tell the user that the app is working and he must wait until it finishes. If the user touch a button while the UIActivityIndicatorView is spinning, when the UIActivityIndicatorView stops, the app remember the user action and responds to it. How can I discard the user interaction that occur while the UIActivityIndicatorView is spinning?
Thanks for reading.
P.D.: Like is commented in this thread, I prefer do not to use any modal solution.
EDITED:
I am currently using this code and it does not work right.
- (void)viewDidAppear:(BOOL)animated {
// The view appears with an UIActivityIndicatorView spinning.
[self showResults]; // The method that takes a long time to finish.
[self.activityIndicator stopAnimating];
// When the showResults method ends, the view shows the buttons to the user.
[self.activityIndicatorView setHidden:YES];
[self.menuButton setEnabled:YES];
[self.menuButton setUserInteractionEnabled:YES];
[self.playButton setEnabled:YES];
[self.playButton setUserInteractionEnabled:YES];
[self.view setUserInteractionEnabled:YES];
[self.interactionView setUserInteractionEnabled:YES];
}
I found these methods very useful:
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
[[UIApplication sharedApplication] endIgnoringInteractionEvents];
In Swift 3.0
To Disable interaction :-
UIApplication.shared.beginIgnoringInteractionEvents()
To restore interaction :-
UIApplication.shared.endIgnoringInteractionEvents()
[_button setUserInteractionEnabled:NO];
That should disable it, just set YES for when you want to user to tap it.
BOOL i_am_ready_to_submit = NO;
-(void)action_finished{
[self.activityIndicator stopAnimating];
i_am_ready_to_submit = YES;
}
-(IBAction)submit_button{
if(i_am_ready_to_submit){
[self submit];
}
}
just add
[self.view setUserInteractionEnabled:NO];
before the
[self.activityIndicator startAnimating];
and reenable it after
[self.activityIndicator stopAnimating];
[self.view setUserInteractionEnabled:YES];
To disable touch event in a view,
[[UIApplication sharedApplication] beginIgnoringInteractionEvents];
To enable touch event in a view
[[UIApplication sharedApplication] endIgnoringInteractionEvents];
For swift 5 you can use:
self.view.isUserInteractionEnabled = false
and to enable all again:
self.view.isUserInteractionEnabled = true
If you have some lag problem, like freeze for about a couple of seconds just put this in:
DispatchQueue.main.async{}
You could disable/enable the UIButtons based on the UIActivityIndicatorView being shown or not. Or, if you just want to "discard the user interaction" while the spinner is shown, in the button handler method:
- (void)buttonTapped:(id)sender {
if ([spinner superview] != nil && [spinner isAnimating]) {
return;
}
// ... the rest of your code
}
This example assumes that when you hide the UIActivityIndicatorView you call one of:
[spinner removeFromSuperview];
or
[spinner stopAnimating];
Use SVProgressHUD WrapperClass It have so many options to show ActivityIndicator
For Source Code Click Here !
[SVProgressHUD showWithMaskType:SVProgressHUDMaskTypeBlack];
use above statement to disable background touches
[SVProgressHUD dismiss]
To enable background touches.
#IBAction func yourButtonPressed(sender: UIButton) {
if self.activityIndicator.isAnimating() {
//remember the action user asked of you using the sender
} else {
//do your stuff
return
}
yourButtonPressed(yourButton)
}
or you code use
self.activityIndicator.animationDidStop to determine when to run your stuff
A quick solution: add a transparent or pseudo transparent view that cover the whole screen. Add your activity indicator on top of this view. When the wait period finishes, remove both views. Get some inspiration.
A better solution, because you can't hide the whole screen in all situations, is to manage the state of the app (ignore actions when the app is 'busy') and disable/enable the appropriate buttons and other controls depending on each app state.
Though answer is replied in earlier response, just like to add for information purpose "[self.activityIndicatorView setHidden:YES];" no need to call this method explicitly, because startAnimating/stopAnimating already take care of this. I'm assuming you are using default value of "hidesWhenStopped" property.

NavigationController is not popping the Pushed View on Back button

Having a simple Navigation Controller in place (starting the Navigation Based Application project) I created a new View with a XIB file.
on my HomeViewController (Home screen with all options as UIButton's I have:
#implementation HomeViewController
-(IBAction) optionChoosed:(UIButton *)button
{
NSString *msg = [NSString stringWithFormat:#"Button: %d", button.tag];
UIAlertView *alert=[[UIAlertView alloc] initWithTitle:#"Hi" message:msg delegate:nil cancelButtonTitle:#"Go away" otherButtonTitles:nil];
switch (button.tag) {
case 13:
// Simple Search
[self loadSimpleSearch]; break;
default:
[alert show];
break;
}
[alert release];
}
-(void)loadSimpleSearch
{
SimpleSearchViewController *controller =
[[SimpleSearchViewController alloc] initWithNibName:#"SimpleSearchViewController" bundle:nil];
[self.navigationController pushViewController:controller animated:YES];
[controller release];
}
witch works great!
it Pushes the View into the front of the stack!
Now, because in my 2nd view SimpleSearchViewController I have self.title = #"myTitle"; I get the Title in the NavigationBar as well the back button (as I have the same setting on the HomeViewController)
I thought that the NavigationViewController would handle the pop of the current view, but it does not.
What do I have to do, to pop the SimpleSearchViewController?
Where do I use [self.navigationController popViewControllerAnimated:YES];
as the view continues there, and ViewDidUnload is never called.
My idea was that this should be handle in the first ViewController, the HomeViewController but I have no idea what is the method I should hook to, and I read the documentation and I can't figure it out :-/
Any help is greatly appreciated, thank you.
HomeViewController
alt text http://cl.ly/XNS/Screen_shot_2010-04-21_at_22.38.51.png
SimpleSearchViewController
alt text http://cl.ly/YDw/Screen_shot_2010-04-21_at_22.40.00.png
SimpleSearchViewController after pressing the Back button
alt text http://cl.ly/XLO/Screen_shot_2010-04-21_at_22.40.21.png
To add the image from a comment that asks if HomeViewController as the root controller for the NavigationViewController
Not sure if this helps but when implementing navigationItem in code, if you don't call the super the popping functionality will not be present
-(UINavigationItem*) navigationItem
{
UINavigationItem* item = [super navigationItem];
item.title = #"search";
return item;
}