Just learning to add actions with code in my .m file and my first attempt throws an exception and crashes the app.
This is an authentication script that I hope will communicate with my web server. Here is the relevant code (this is all in the .m file, very simple .h file):
.h (header) file:
#import <UIKit/UIKit.h>
@interface Login_ViewController : UIViewController <UITextFieldDelegate>
@end
.m (implementation) file:
- (void)viewDidLoad {
UILabel *emailLabel = [[UILabel alloc] initWithFrame:CGRectMake(31.0f, 75.0f, 256.0f, 20.0f)];
emailLabel.text = @"Email Address";
emailLabel.backgroundColor = [UIColor grayColor];
emailLabel.textColor = [UIColor whiteColor];
UITextField *emailField = [[UITextField alloc] initWithFrame:CGRectMake(31.0f, 100.0f, 256.0f, 32.0f)];
emailField.delegate = self;
emailField.placeholder = @"Enter email address";
emailField.borderStyle = UITextBorderStyleRoundedRect;
[self.view addSubview:emailLabel];
[self.view addSubview:emailField];
UILabel *passLabel = [[UILabel alloc] initWithFrame:CGRectMake(31.0f, 175.0f, 256.0f, 20.0f)];
passLabel.text = @"Password";
passLabel.backgroundColor = [UIColor grayColor];
passLabel.textColor = [UIColor whiteColor];
UITextField *passField = [[UITextField alloc] initWithFrame:CGRectMake(31.0f, 200.0f, 256.0f, 32.0f)];
passField.delegate = self;
passField.placeholder = @"Enter Password";
passField.borderStyle = UITextBorderStyleRoundedRect;
passField.secureTextEntry = YES;
UIButton *loginButton = [[UIButton alloc] initWithFrame:CGRectMake(31.0f, 275.0f, 256.0f, 32.0f)];
[loginButton setTitle:@"Login" forState:UIControlStateNormal];
[loginButton addTarget:self action:@selector(authenticate) forControlEvents:UIControlEventTouchUpInside];
[self.view addSubview:passLabel];
[self.view addSubview:passField];
[self.view addSubview:loginButton];
[self.view setBackgroundColor: [UIColor grayColor]];
UIAlertView *noAccount = [[UIAlertView alloc] initWithTitle:@"Welcome to T-of-U" message:@"Please enter your TofU credentials." delegate:self cancelButtonTitle:@"continue" otherButtonTitles: nil];
[noAccount show];
[super viewDidLoad];
}
also in the .m file (IBAction for the button):
-(IBAction)authenticate:(id)sender{
// This will be the validation code
// if we validate we will set the default Setting with accountID here.
UIAlertView *auth1 = [[UIAlertView alloc] initWithTitle:@"You clicked a button" message:@"Oh, do you want to login do you?" delegate:self cancelButtonTitle:@"Sure.. Why not!" otherButtonTitles: nil];
[auth1 show];
}
I am using a storyboard with a View that has a custom class of login_ViewController and it loads successfully based on a check for a local setting for account ID. This window is only pulled up if they have not logged in before, so I can authenticate and get that account ID to store locally. I am still experimenting with programmatically creating all these items as you can see in the viewDidLoad section.
Is this failing because I don’t have the button/IBAction reference in the .h file , or is it ok to use the addTarget method where its all in the .m file?
Crash info from the log:
2012-01-08 04:54:32.868 TofU-5[10452:10103] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[Login_ViewController authenticate]: unrecognized selector sent to instance 0x6c94780'
Your fix may be as easy as:
(add a COLON after the
authenticatename in your@selector). If a method takes any parameter, there will be a colon after it and for the run time environment to be able to send a message to it, that colon needs to be included in the selector of the action target.I hope this makes sense and helps you out!
p.s. it wouldn’t hurt to add
to the .h file.
IBActionhere is an abbreviation for InterfaceBuilder-Action so this actually helps a lot more if you’re building the interface in a XIB file. Because you’re setting the target programatically, you could just use-(void) authenticate(no colon, because your method uses or needs no parameters), but don’t do this yet until you get more overall experience with Objective C coding and actions.