I have a view controller for registering a PFuser. I also have a view overlaid on the same view controller that occupies the entire frame but adjusted to be on the right side of the view controller.
This login view appears upon clicking "already registered" button the view controller. I also have the code to fill in the frame with view entirely.
The issue is: whenever I click on username textfield on the view to enter login credentials, it goes back to the view controller asking to register.
//"I am already registered" button action method
- (IBAction)registeredButton:(id)sender {
[UIView animateWithDuration:0.3 animations:^{
_loginOverlayView.frame = self.view.frame;
}];
}
//login button method
- (IBAction)loginButton:(id)sender {
[PFUser logInWithUsernameInBackground:_loginUsernameField.text password:_loginPasswordField.text block:^
(PFUser * user, NSError * error) {
if(!error)
{
NSLog(#"Login user");
[self performSegueWithIdentifier:#"login" sender:self];
_usernameField.text=nil;
_passwordField.text=nil;
_emailField.text=nil;
_reEnterPasswordField.text=nil;
_loginPasswordField.text=nil;
_loginUsernameField.text=nil;
}
else
{
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Oops!" message:#"Sorry we had problem logging you in!" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alert show];
}
}];
}
Related
I'm creating a small app which verifies username and password from plist and shows user profile in other ViewController or (next screen).
I added a Login Button which validates username and password from user input with data stored in Plist(property list).
I also added a condition for show alert message when user entered wrong password or logged in successfully.
I created an another ViewController and connects with main ViewController via Login button.
my problem is when i clicked LOGIN button, it automatically moves to next view controller without checking username password and also not shows alert.
how to go next ViewController after validation completes and alert view done.
I need code in Objective-C
- (IBAction)submitButton:(UIButton *)sender {
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"profileDetails" ofType:#"plist"]];
NSString *usernameentered = dict[#"user"][#"username"];
NSString *passwordentered = dict[#"user"][#"password"];
if ([self.username.text isEqualToString:usernameentered] && [self.password.text isEqualToString:passwordentered]) {
NSLog(#"login sucessfull");
UIAlertController* alert = [UIAlertController alertControllerWithTitle:#"Attention"
message:#"LOGIN SUCCESS"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#"OKAY" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
}else if ([self.username.text isEqual:#""] && [self.password.text isEqual:#""]) { UIAlertController* alert = [UIAlertController alertControllerWithTitle:#"Attention"
message:#"PLEASE ENTER Valid EMAIL AND PASSWORD"
preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:#"Okay ! Got it" style:UIAlertActionStyleDefault
handler:^(UIAlertAction * action) {}];
[alert addAction:defaultAction];
[self presentViewController:alert animated:YES completion:nil];
}
}
I think you have use 'show' segue in tap of login button tap.you need to use custom segue for it. You can setup custom segue as below.
Step 1:
Give custom segue to current controller to target controll. You can also see in below image.
Step 2
- Give any unique identifier to segue. You can also see in below image.
Then use below code for redirection when credential is valid.
[self performSegueWithIdentifier:#"NextVC" sender:self];
"i created an another view controller and connects with main view controller via Login button"
If you're using segue to navigate then you should write code inside prepareForSegue or shouldPerformSegueWithIdentifier method. Otherwise you can navigate to ViewController through code inside submit button action.
Try writing this code inside shouldPerformSegueWithIdentifier method, it should work
- (IBAction)submitButton:(UIButton *)sender {
//Get stored username and password
NSDictionary *dict = [[NSDictionary alloc] initWithContentsOfFile:[[NSBundle mainBundle]pathForResource:#"profileDetails" ofType:#"plist"]];
NSString *usernameentered = dict[#"user"][#"username"];
NSString *passwordentered = dict[#"user"][#"password"];
if ([self.username.text isEqual:nil] || [self.username.text isEqual:#""]) {
//Show alert for empty username
}
else if ([self.password.text isEqual:nil] || [self.password.text isEqual:#""]) {
//Show alert for empty username
}
else if (![self.username.text isEqualToString:usernameentered]) {
//Show alert for wrong username
}
else if (![self.password.text isEqualToString:passwordentered]) {
//Show alert for wrong password
}
else {
//All validation is right.
//Move to other Viewcontroller
UIStoryboard *main = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
NSString *Identifier = #"ViewController"; //Same as in storyboard
UIViewController *vc = [main instantiateViewControllerWithIdentifier:Identifier];
[self.navigationController pushViewController:vc animated:true]; //If you want to push
//[self.navigationController presentViewController:vc animated:YES completion:nil] //If you want to present
}
}
I have two different view controllers, one for a dashboard and one for registration. I do not want the user to be able to interact with anything on the dashboard until the user logs in through an alertview. So every time the user navigates back to the dashboard or presses cancel and they are not logged in, I want the login alert to popup.
This works perfectly in all cases, including when the user hits the back button on the navigation bar in the registration view, but does not work when the user clicks OK on the alert in the registration page.
the dashboard view contains this code:
#property(strong) UIAlertView * alert;
//...
-(void)viewWillAppear:(BOOL)animated
{
user_email = [[NSUserDefaults standardUserDefaults] stringForKey:#"email"];
if ( user_email==nil ){
[self auto_login];
} else //...
}
-(void)auto_login
{
alert = [[UIAlertView alloc] initWithTitle:#"Login" message:nil delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Login",#"Forgot Password",#"Register",nil];
alert.alertViewStyle = UIAlertViewStyleLoginAndPasswordInput;
[alert show];
}
-(void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
switch (buttonIndex) {
case 0:
{
self.debug.text = #"Cancel";
[self auto_login];
break;
}
//...
default:
{
self.debug.text = #"Register";
[self nav_register];
break;
}
}
}
-(void)nav_register
{
RegisterProfileController *rvc = [[RegisterProfileController alloc] init];
[self.navigationController pushViewController:rvc animated:YES];
}
The registration view controller contains this code:
-(void)catch_registration
{
NSString *response = [[NSString alloc] initWithData:self.httpdata encoding:NSASCIIStringEncoding];
if( [response isEqualToString:#"OK"] ){
UIAlertView *successAlert = [[UIAlertView alloc] initWithTitle:#"Success" message:#"..." delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
successAlert.alertViewStyle = UIAlertViewStyleDefault;
[successAlert show];
}
else //...
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if ([alertView.title isEqualToString:#"Success"])
[self.navigationController popViewControllerAnimated:TRUE];
}
After debugging, I know that after clickedButtonAtIndex runs in the registration view controller, [alert show] runs in the dashboard view controller, and clickedButtonAtIndex does NOT run in the dashboard view controller, but no alert shows up.
Why isn't the alert showing or how can I debug this further?
If clickedButtonAtIndex "does NOT run" as you said, then the delegate might not be set correctly. In addition, you should likely move the code from viewWillAppear: to viewDidAppear: because the view is not in the view hierarchy at that point. Your solution might be a combination of these two issues.
Im calling popToRootViewController in a UiViewController that is acting as a sign-in page. The method is called once the backend has authenticated the user and will now allow the user to access their account. When the root view Controller is shown again, I get the following two errors.
nested push animation can result in corrupted navigation bar
Finishing up a navigation transition in an unexpected state. Navigation Bar subview tree might get corrupted.
Here is the code for signing in a user.
- (IBAction)signIn:(id)sender
{
NSString *userName = [self.emailTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
NSString *password = [self.passwordTextField.text stringByTrimmingCharactersInSet:[NSCharacterSet whitespaceAndNewlineCharacterSet]];
if (userName.length == 0 || password.length ==0){
UIAlertView *alertView = [[UIAlertView alloc]initWithTitle:#"Invalid Login Credentials" message:#"Make sure you have entered a valid Username and Password" delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil];
[alertView show];
}else{
[PFUser logInWithUsernameInBackground:userName password:password block:^(PFUser *user, NSError *error) {
if (error){
UIAlertView *errorAlertView = [[UIAlertView alloc]initWithTitle:#"Something went wrong" message:[error.userInfo objectForKey:#"error"] delegate:nil cancelButtonTitle:#"ok" otherButtonTitles:nil];
[errorAlertView show];
}else{
//dispatch_sync(dispatch_get_main_queue(), ^{
[self.navigationController popViewControllerAnimated:YES];
//});
}
}];
}
}
The rootViewController is the initial view that the app launches into, and there it checks to see if there is a current user and if not the user will be sent to the login page. I do notice that by going into the Login page, there is a back arrow at the top of the navigation bar to go back to the rootViewController. Once The user signs in, there is now a back button in the same place that wants to take the user back to the LoginViewController which has been popped. I think this is where the issue is occurring.
This error is raised when you try to push several view controllers or pop more than one view controller. Are you sure the viewWillAppear method of your rootViewController is not attempting to push a view controller ? If so, you're attempting to push a view controller while another one is being popped. Hope this may help you!
I have 2 view controllers, ViewController 1(VC1) and 2(VC2). In VC2 I have a back and done button. On clicking back button it goes directly to VC1 and on done it makes an api call and when it gets a response it shows an alert view and clicking ok goes back to VC1. Now when I make a api call a loading bar shows up and disappears when I get response and shows the AlertView. But if during that fraction of second when the loading disappears and AlertView is going to be popped up if I click on back and the view changes to VC1, the alert appears on VC1 and results in a crash.
This is a rare case as no user will purposely try for it but I was wondering if that crash can be managed without disabling the back button. I think there can be other instance such cases like if we are making an asynchronous calls and if the user is allowed to use UI while waiting for response and if any error alert that was suppose to show on one ViewController shows up in another may result in crash since the delegate that alert is referring to is that of the previous view controller. So is there any way to handle this kind of crash efficiently?
//Alert View sample
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[[message objectAtIndex:1] capitalizedString] message:[message objectAtIndex:0] delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil] ;
[alert setTag:701];
[alert show];
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if ([alertView tag] == 701)
if (buttonIndex == 0)
{
[self.navigationController popViewControllerAnimated:YES];
}
}
The proper way to fix this problem is to use an instance variable to keep a reference to the alert view.
This instance variable should be set to nil in the alertView:didDismissWithButtonIndex: delegate method.
In the view controller's dealloc method, you call dismissWithClickedButtonIndex:animated: if the instance variable is still set.
Assume _alertView is the instance variable.
Create the alert:
_alertView = [[UIAlertView alloc] initWithTitle:[[message objectAtIndex:1] capitalizedString] message:[message objectAtIndex:0] delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil] ;
[_alertView setTag:701];
[_alertView show];
Update your existing alertView:clickedButtonAtIndex: method:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if ([alertView tag] == 701) {
_alertView.delegate = nil;
_alertView = nil;
if (buttonIndex == 0) {
[self.navigationController popViewControllerAnimated:YES];
}
}
}
Add:
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
_alertView = nil;
}
Add:
- (void)dealloc {
if (_alertView) {
_alertView.delegate = nil;
[_alertView dismissWithClickedButtonIndex:_alertView.cancelButtonIndex animated:NO];
_alertView = nil;
}
}
Once the user of my app has sent an email and has seen a UIAlert informing them their email has been sent successfully, id like them to then be taken back to a home screen via a segue. at the moment the user has to push a back button to achieve this.
I get the feeling it should be implemented in the mailComposeController method, but I've never programatically activated a segue.
my code is given below:
-(void)mailComposeController:(MFMailComposeViewController *)controller didFinishWithResult:(MFMailComposeResult)result error:(NSError *)error{
switch (result) {
case MFMailComposeResultCancelled:
{
[self dismissViewControllerAnimated:YES completion:nil];
}
break;
case MFMailComposeResultSent:
{
[self dismissViewControllerAnimated:YES completion:nil];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Disclaimer", "")
message:NSLocalizedString(#"Thank you for Dobbing in a Hoon. You will shortly receive an email from Council. Please be aware that the Police are responsible for actioning your requests.", "")
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alert show];
break;
}
case MFMailComposeResultFailed:
{
[self dismissViewControllerAnimated:YES completion:nil];
UIAlertView *alert_failed = [[UIAlertView alloc] initWithTitle:NSLocalizedString(#"Email Failure", "")
message:NSLocalizedString(#"Your Email Failed to send - Please try Again", "")
delegate:nil
cancelButtonTitle:#"OK"
otherButtonTitles: nil];
[alert_failed show];
break;
}
default:
break;
}
- (void)alertView:(UIAlertView *)alert clickedButtonAtIndex:(NSInteger)buttonIndex;
{
if (buttonIndex != alert.cancelButtonIndex) {
[self performSegueWithIdentifier:#"hoonToHome" sender:self];
}
}
If you need only to pop to your home screen and if the home screeen is nav controllers root view controller try
[self.navigationContoller popToRootViewControllerAnimated:YES];
Or if you have a sugue for that use
[self performSegueWithIdentifier:#"yourSegueID" sender:nil];
UPDATE
If you want the transition after alertview's ok click the set alert delegate to self and implemet delegate method
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
in this Method add the above code.
I you want immediate transition then place it before or after [alert show];
First you need to set the delegate of the UIAlertView to self and implement the UIAlertView delegate methods.
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex;
Then to call your segue.
[self performSegueWithIdentifier:#"someIdentifierDefinedInStoryboard" sender:self];
Or if you're referring to the standard back action of a navigation controller
[self.navigationController popToRootViewControllerAnimated:YES];