I have this UIButton defined in my .h file:
@property (nonatomic,strong) UIButton *loginButton;
- (void)LoginButtonPressed:(UIButton *)sender;
and have it created in my .m file:
@synthesize loginButton;
loginButton = [UIButton buttonWithType:UIButtonTypeCustom];
[loginButton setFrame:CGRectMake(150.0f, 131.0f, 105.0f, 35.0f)];
[loginButton setBackgroundImage:[UIImage imageNamed:@"black_button.png"] forState:UIControlStateNormal];
[loginButton setTitle:@"Login" forState:UIControlStateNormal];
[loginButton setTitleColor:[UIColor whiteColor] forState:UIControlStateNormal];
[loginButton addTarget:self action:@selector(LoginButtonPressed:) forControlEvents:UIControlEventTouchUpInside];
- (void)LoginButtonPressed:(UIButton *)sender
{
[self CreateActivityIndicator];
[self performSelector:@selector(Login) withObject:nil afterDelay:0.5];
}
and I have a method called login and on login I want to remove the login button from superview.
[self.loginButton removeFromSuperview];
but all of a sudden (as of yesterday) my app started crashing and throwing an error on this line:
@property (nonatomic,strong) UIButton *loginButton;
Thread 1: EXC_BAD_ACCESS(code=1, address0x10000010)
Why is this happening? and how can I fix it? I did change my login method around yesterday to use AFNetworking, could that be it?
Just in case, here is my full method:
- (void)Login
{
NSString *rawString = [self.idTextField text];
NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
[self.idTextField setText:[rawString stringByTrimmingCharactersInSet:whitespace]];
[userName UserLogin:self.idTextField.text andPassWordExists:self.passwordTextField.text completionHandler:^(id responseObject, NSError *error) {
if (responseObject) {
[self.idTextField removeFromSuperview];
[self.passwordTextField removeFromSuperview];
[self.loginButton removeFromSuperview];
self.idTextField = nil;
self.passwordTextField = nil;
self.loginButton = nil;
[self CreateMenu];
}else{
[self CustomAlert:@"Sorry Login Failed, User and/or Passsword Incorrect"];
}
}];
[indicatorView stopAnimating];
[indicatorView removeFromSuperview];
indicatorView = nil;
[loadingView removeFromSuperview];
loadingView = nil;
}
and here is what is triggering it:
-(void)UserLogin:(NSString *)user andPassWordExists:(NSString *)password completionHandler:(void (^)(NSArray *resultsObject, NSError *error))completionHandler
{
NSURL *url = [NSURL URLWithString:kIP];
NSURLRequest *request = [NSURLRequest requestWithURL:url];
AFHTTPRequestOperation *operation = [[AFHTTPRequestOperation alloc]
initWithRequest:request];
NSURLCredential *credential = [NSURLCredential
credentialWithUser:user
password:password
persistence:NSURLCredentialPersistenceForSession];
[operation setCredential:credential];
[[NSOperationQueue mainQueue] addOperation:operation];
[operation setCompletionBlockWithSuccess:^(AFHTTPRequestOperation *operation, id responseObject) {
if (completionHandler) {
completionHandler(responseObject, nil);
}
} failure:^(AFHTTPRequestOperation *operation, NSError *error) {
if (completionHandler) {
completionHandler(nil, error);
}
}];
[operation start];
}
Here is how my button is getting added to the view, along with the 2 text items:
//add all controls to the loginView
[loginMenuView addSubview:self.idTextField];
[loginMenuView addSubview:self.passwordTextField];
[loginMenuView addSubview:self.loginButton];
UPDATE
I was able to resolve this issue by doing the following:
taking out self.loginButton = nil;
from my Login Method, so it looks like this:
- (void)Login
{
NSString *rawString = [self.idTextField text];
NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
[self.idTextField setText:[rawString stringByTrimmingCharactersInSet:whitespace]];
[userName UserLogin:self.idTextField.text andPassWordExists:self.passwordTextField.text completionHandler:^(id responseObject, NSError *error) {
if (responseObject) {
[self.idTextField removeFromSuperview];
[self.passwordTextField removeFromSuperview];
[self.loginButton removeFromSuperview];
self.idTextField = nil;
self.passwordTextField = nil;
//self.loginButton = nil;
[self CreateMenu];
[indicatorView stopAnimating];
[indicatorView removeFromSuperview];
indicatorView = nil;
[loadingView removeFromSuperview];
loadingView = nil;
}else{
[self CustomAlert:@"Sorry Login Failed, User and/or Passsword Incorrect"];
[indicatorView stopAnimating];
[indicatorView removeFromSuperview];
indicatorView = nil;
[loadingView removeFromSuperview];
loadingView = nil;
}
}];
}
and taking out [self.loginButton removeFromSuperview];
and self.loginButton = nil;
from my viewWillDisappear
method like so:
- (void)viewWillDisappear:(BOOL)animated
{
[super viewWillDisappear:animated];
userName = nil;
[[NSNotificationCenter defaultCenter]removeObserver:self];
[self.idTextField removeFromSuperview];
[self.passwordTextField removeFromSuperview];
//[self.loginButton removeFromSuperview];
[self.menu removeFromSuperview];
[logoutButton removeFromSuperview];
//set every control to nil
self.idTextField = nil;
self.passwordTextField = nil;
//self.loginButton = nil;
self.menu = nil;
menuItems = nil;
textfieldNavigatorView = nil;
}
this has solved my problem, I just want to know if this is the best solution.
What I think is happening is that your loginButton is tied to your indicatorView or loadingView.
Since you're using a completion handler, the code inside of it is going to run asynchronously. That means that your
indicatorView = nil
or your
loadingView = nil
is being triggered before your loginButton is being removed. If loginButton is a subview of one of those views, nothing has reference to it anymore, thus you get a BAD_ACCESS. Make sure you put the last 5 lines of code (the ones that deal with loadingView and indicatorView) inside of your completion handler like so:
- (void)Login
{
NSString *rawString = [self.idTextField text];
NSCharacterSet *whitespace = [NSCharacterSet whitespaceAndNewlineCharacterSet];
[self.idTextField setText:[rawString stringByTrimmingCharactersInSet:whitespace]];
[userName UserLogin:self.idTextField.text andPassWordExists:self.passwordTextField.text completionHandler:^(id responseObject, NSError *error) {
if (responseObject) {
[self.idTextField removeFromSuperview];
[self.passwordTextField removeFromSuperview];
//access the loginButton while it still has reference
[self.loginButton removeFromSuperview];
self.idTextField = nil;
self.passwordTextField = nil;
//access the loginButton while it still has reference
self.loginButton = nil;
//Then remove these views
[indicatorView stopAnimating];
[indicatorView removeFromSuperview];
indicatorView = nil;
[loadingView removeFromSuperview];
loadingView = nil;
[self CreateMenu];
}else{
[self CustomAlert:@"Sorry Login Failed, User and/or Passsword Incorrect"];
}
}];
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.