how to call a storyboard scene conditionally from a button - iphone

I have an application who's first scene is a login screen. On pressing the login button, if the username and password are correct, the next scene should get called. Otherwise an alert is shown. But I am unable to figure out how to get the next scene conditionally.
if ([jsonDict valueForKey:#"success"] && [jsonDict valueForKey:#"redirect"]) {
NSLog(#"%#", [jsonDict valueForKey:#"success"]);
NSLog(#"%#", [jsonDict valueForKey:#"redirect"]);
NSString *redirect = [jsonDict valueForKey:#"redirect"];
[self performSegueWithIdentifier:#"next" sender:self];
}
else {
NSArray *jsonArray = [jsonDict valueForKey:#"errors"];
NSString *err = [jsonArray objectAtIndex:0];
NSLog(#"%#", err);
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Invalid Credentials!" message:err delegate:nil cancelButtonTitle:#"OK" otherButtonTitles: nil];
[alert show];
}

Set up a Segue to the next viewcontroller in your storyboard and give that segue a unique identifier. Then, if username and password are ok, just call
[self performSegueWithIdentifier:#"yourSegueIdentifier" sender:self];

Use below code:
- (void)validateLogin{
//code to check username and password are correct
if(correct){
[self performSegueWithIdentifier:#"SignInToNextScreen" sender:self];
}else{
UIAlertView *myalert = [[UIAlertView alloc]initWithTitle:#"Login Failed" message:#"Invalid Username/Password" delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil, nil];
}
}
//SignInToNextScreen is a segue identifier for manually triggered segue.
Please see the attached screen shot

Related

Number keypad jumping after UIAlertview

I have a login screen that shows an alert when the user gets the password wrong on a number of occasions. On clicking one of the buttons, another alert view is presented to confirm, if I press the cancel button on this second alert view, the number keypad bounces from the bottom of the screen back up to its original position. No code is being executed during this second alert response. Can someone help?
if (loginCount < 5) {
// Display alert to user
UIAlertView *loginError = [[UIAlertView alloc] initWithTitle:#"Login Failure" message:#"You have entered an incorrect passcode. Please try again." delegate:self cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[loginError show];
} else {
// Display alert to user, including option to reset the app as they have 5 or more login failures
UIAlertView *loginError = [[UIAlertView alloc] initWithTitle: #"Login Failure" message: #"You have entered an incorrect passcode on 5 or more occasions. Please try again or reset the app." delegate: self cancelButtonTitle: #"Try Again" otherButtonTitles: #"Reset App", nil]
[loginError show];
}
// Clear password fields
[self clearPasswordFields];
[passcode1 becomeFirstResponder];
// Increment the login count
loginCount++;
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
// If the user has chosen to reset the app, alert with a confirmation first before resetting
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if ([title isEqualToString:#"Reset App"]) {
// Create alert to give the user the choice to confirm reset
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Confirm Reset" message:#"Are you sure you wish to Reset?" delegate:self cancelButtonTitle:#"No" otherButtonTitles:#"Yes", nil];
[alert show];
} else if ([title isEqualToString:#"Yes"] && buttonIndex == 1) {
[Utilities resetApp];
[self dismissViewControllerAnimated:NO completion:nil];
}
}
This is how i will do it.
in the header file:
UIAlertView *loginError;
in the implementation file:
-(void)textFieldDidEndEditing:(UITextField *)textField
{
if (loginCount < 5) {
// Display alert to user
loginError = [[UIAlertView alloc] initWithTitle:#"Login Failure" message:#"You have entered an incorrect passcode. Please try again." delegate:self cancelButtonTitle:#"Dismiss" otherButtonTitles:nil];
[loginError show];
} else {
// Display alert to user, including option to reset the app as they have 5 or more login failures
loginError = [[UIAlertView alloc] initWithTitle: #"Login Failure" message: #"You have entered an incorrect passcode on 5 or more occasions. Please try again or reset the app." delegate: self cancelButtonTitle: #"Try Again" otherButtonTitles: #"Reset App", nil]
[loginError show];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
// If the user has chosen to reset the app, alert with a confirmation first before resetting
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if ([title isEqualToString:#"Reset App"]) {
[self showSecondAlert];
} else if ([title isEqualToString:#"Yes"] && buttonIndex == 1) {
[Utilities resetApp];
[self dismissViewControllerAnimated:NO completion:nil];
}else{
[self clearPasswordFields];
[passcode1 becomeFirstResponder];
}
}
-(void)showSecondAlert
{
//make sure you dismiss the old alertview first
[loginError dismissWithClickedButtonIndex:0 animated:NO];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Confirm Reset" message:#"Are you sure you wish to Reset?" delegate:self cancelButtonTitle:#"No" otherButtonTitles:#"Yes", nil];
[alert show];
}
Hope this helps...

UIAlertView on main queue crashing.

I have an issue showing a UIAlertView on the main thread. I'm not sure why but it keeps crashing, despite me running on the main thread. The following block is on the background thread, but I have the alert on the main as below:
void (^removeFromCalendar)(NSString *, NSString *, EKEventStore *) = ^(NSString *error, NSString *eventKey, EKEventStore *eventDB) {
EKEvent *myEvent = [eventDB eventWithIdentifier:eventKey];
NSError *err = noErr;
if(myEvent != NULL && myEvent != (id)[NSNull null]) {
[eventDB removeEvent:myEvent span:EKSpanThisEvent error:&err];
} else {
// Event was not found, nothing to do
return;
}
[eventDB release];
if (!err || err == noErr) {
NSLog(#"Deleted event %#", myEvent.title);
// Show alert on the main thread
dispatch_async(dispatch_get_main_queue(), ^{
// Showing the alert for unattending
NSString *resultString = #"This event was removed from your calendar.";
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:#"Info" message:resultString delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil] autorelease];
[alert show];
});
return;
}
error = err.description;
};
If I comment out the bottom where it shows the alert, everything is fine. But for the alert, I keep getting a EXC_BAD_ACCESS error. Can somebody explain why? It's on the correct thread, and I cant for the life of me understand where the memory issue could come from!
May be you view is being released when you finish until you finish with the background queue. So, for safety why dont you use it like this;
...........
UIViewController __weak *myController = self;
dispathch_async(backgroundQueue, ^{
UIViewController __strong *myStrongController = myController;
...............
dispatch_async(dispatch_get_main_queue(), ^{
if(myStrongController){
// Showing the alert for unattending
NSString *resultString = #"This event was removed from your calendar.";
UIAlertView *alert = [[[UIAlertView alloc] initWithTitle:#"Info" message:resultString delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil] autorelease];
[alert show];
}
});
}).
This is how you present an alert view:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"<#(NSString *)#>" message:#"<#(NSString *)#>" delegate:self cancelButtonTitle:#"<#(NSString *)#>" otherButtonTitles:nil];
[alert show];
[alert release];
Instead of using dispatch_async, why not use the objective C call:
[self performSelectorOnMainThread
You might have to package it up in its own method. Alternatively, call it using:
[self performSelector:#selector(myAlertMethod) withObject:nil afterDelay:0.25]
These methods have been tried and true since day 1.

UIAlertView didmissWithClickedButtonIndex does not dismiss the alert

From my object that handles the web service connection, when the network fails, I pass an alert to the view controller that uses the web service object.
WebServiceObject:
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Error" message:[NSString stringWithFormat:#"Connection failed! You must be connected to a Wifi source to download data. Please reconnect to a Wifi source and try again later."] delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil];
NSDictionary *alertDict = [NSDictionary dictionaryWithObjectsAndKeys:alert, #"AlertView", nil];
[[NSNotificationCenter defaultCenter] postNotificationName:DisplayAlertNotification object:self userInfo:alertDict];
ViewController:
- (void)displayAlert:(NSNotification *)notification {
NSDictionary *dict = [notification userInfo];
if ([[dict objectForKey:#"AlertView"] isKindOfClass:[UIAlertView class]]) {
UIAlertView *alert = [dict objectForKey:#"AlertView"];
NSNumber *theTag = [dict objectForKey:#"AlertTag"];
NSLog(#"%i", [theTag integerValue]);
alert.tag = [[dict objectForKey:#"AlertTag"] integerValue];
[alert show];
}
}
- (void)removeAlert:(NSNotification *)notification {
NSDictionary *dict = [notification userInfo];
if ([[dict objectForKey:#"AlertTag"] isKindOfClass:[NSNumber class]]) {
NSNumber *theTag = [dict objectForKey:#"AlertTag"];
UIAlertView *alert = (UIAlertView *)[self.view viewWithTag:[theTag integerValue]];
// Not sure why but my alert is nil at this point
[alert dismissWithClickedButtonIndex:0 animated:YES];
}
}
I also use the removeAlert method in the same way to remove the alert programmatically. The goal of this is so if the network failed, but the user didn't click Ok yet, and then the network came back on, I would dismiss the Network Failed alert, and show the Network Resumed alert. It works except after it dismisses the alert and shows the Network Resumed, once the user clicks Ok on the Network Resumed, the original Network Failed comes back up just once. If the user clicked Ok while the Network Failed was presented, it never comes back up.
Am I dismissing the alert correctly this way? Thanks.
Edit: I can get it to work by just saving a reference in the WebServiceObject and dismissing it that way.
you set the alert to nil, so it do nothing
alert = nil;
[alert dismissWithClickedButtonIndex:0 animated:YES];

UIActionSheet isn't loading actions for button indexes?

I have set up some code so that when two separate buttons are tapped on a UIActionSheet, there will be two different actions. Unfortunately nothing happens when the buttons are pressed. The UIActionSheet just unloads as if a cancel button had been pressed.
Here's my code:
- (IBAction)saveFile:(id)sender {
UIActionSheet *saveFileSheet = [[[UIActionSheet alloc]
initWithTitle:#"iDHSB Download Centre"
delegate:nil
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Download File", #"Show My Files", nil]
autorelease];
[saveFileSheet showInView:webView];
}
-(void)actionSheet:(UIActionSheet *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSLog(#"Action Sheet Button Pressed");
if(buttonIndex == 1) {
NSLog(#"Show My Files");
[self.window presentModalViewController:savedFiles animated:YES];
}
if(buttonIndex == 2){
NSLog(#"Saving File");
// Get the URL of the loaded ressource
NSURL *theResourcesURL = [[webView request] URL];
// Get the filename of the loaded ressource form the UIWebView's request URL
NSString *filename = [theResourcesURL lastPathComponent];
NSLog(#"Filename: %#", filename);
// Get the path to the App's Documents directory
NSString *docPath = [self documentsDirectoryPath];
// Combine the filename and the path to the documents dir into the full path
NSString *pathToDownloadTo = [NSString stringWithFormat:#"%#/%#", docPath, filename];
// Load the file from the remote server
NSData *tmp = [NSData dataWithContentsOfURL:theResourcesURL];
// Save the loaded data if loaded successfully
if (tmp != nil) {
NSError *error = nil;
// Write the contents of our tmp object into a file
[tmp writeToFile:pathToDownloadTo options:NSDataWritingAtomic error:&error];
if (error != nil) {
UIAlertView *filenameErrorAlert = [[UIAlertView alloc] initWithTitle:#"Error Saving" message:[NSString stringWithFormat:#"The file %# could not be saved. Please try again.", filename] delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[filenameErrorAlert show];
[filenameErrorAlert release];
NSLog(#"Failed to save the file: %#", [error description]);
} else {
// Display an UIAlertView that shows the users we saved the file :)
UIAlertView *filenameAlert = [[UIAlertView alloc] initWithTitle:#"File saved" message:[NSString stringWithFormat:#"The file %# has been saved.", filename] delegate:self cancelButtonTitle:#"OK" otherButtonTitles:nil];
[filenameAlert show];
[filenameAlert release];
}
} else {
NSLog(#"Error, file could not be saved");
}
}
else
{
NSLog(#"Error, could not find button index!");
}
}
Thanks,
James
You have set the UIActionSheet delegate to nil. In this context, you want to set it to self.
You have to set the delegate to self
UIActionSheet *saveFileSheet = [[[UIActionSheet alloc]
initWithTitle:#"iDHSB Download Centre"
delegate:self
cancelButtonTitle:#"Cancel"
destructiveButtonTitle:nil
otherButtonTitles:#"Download File", #"Show My Files", nil]
autorelease];
You’re creating the action sheet with a nil delegate, so the delegate methods you implemented will never get called. Pass self as the delegate in the action sheet’s initializer and it should work.

How should I properly format this code?

I've a small issue here. I am using an if statement with UIAlertView and I have two situations, both result in UIAlertViews. However, in one situation, I want to dismiss just the UIAlertView, the other, I want the UIAlertView to be dismissed and view to return to root view.
This code describes is:
if([serverOutput isEqualToString:#"login.true"]){
[Alert dismissWithClickedButtonIndex:0 animated:YES];
[UIApplication sharedApplication].networkActivityIndicatorVisible = NO;
UIAlertView *success = [[UIAlertView alloc] initWithTitle:#"Success" message:#"The transaction was a success!"
delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[success show];
[success release];
} else {
UIAlertView *failure = [[UIAlertView alloc] initWithTitle:#"Failure" message:#"The transaction failed. Contact sales operator!"
delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
[failure show];
[failure release];
}
}
-(void)alertView: (UIAlertView *)success clickedButtonAtIndex: (NSInteger)buttonIndex{
switch(buttonIndex) {
case 0: {
[self.navigationController popToRootViewControllerAnimated:YES];
}
}
}
So, in both cases, they follow the above action, but obviously, that's not what I want. Any ideas on what I do here?
You will have to differentiate between the 2 uialertview in your clickedButtonAtIndex: method.
Use the tag property to differentiate.
When you create the alerview assign a tag id to them:
UIAlertView *success = [[UIAlertView alloc] initWithTitle:#"Success" message:#"The transaction was a success!" delegate:self cancelButtonTitle:#"Ok" otherButtonTitles:nil, nil];
success.tag = 1;
[success show];
Similarly,
failure.tag = 2;
Then you switch on the tag ids
switch(alertView.tag){
case 1: //dismiss alertview
case 2: //dismiss alertview and return to root view
}
You could paste your code in Eclipse, and press ctrl+i.