0

I'v encountered EXC_BAD_ACCESS error in my app. Or to be more specific in one of my classes. It is Custom UIAlertView class. I couldn't catch when it throws EXC_BAD_ACCESS in usage. Sometimes it works great just as expected, and in all suden it craches... Here is whole class

@implementation AlertPassword
int counter = 3;
@synthesize done;
@synthesize alertText;
@synthesize msg;
- (void) showAlert :(NSString*) title
{
    if(counter != 3){
        if(counter == 1)
        {
            NSString *msgs = @"Last warning";
            msg = msgs;
        }
        else
        {
            NSString *msgs = [NSString stringWithFormat:@"WRONG PIN. %d times remaining",counter];
            msg = msgs;

        }
    }
    else
    {
        NSString *msgs = @"Enter your pin";
        msg = msgs;
    }
    UIAlertView * alert = [[UIAlertView alloc] initWithTitle:@"Security" message:msg delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles: nil];
    _alert = alert;
    _alert.alertViewStyle = UIAlertViewStyleSecureTextInput;
    alertText = [_alert textFieldAtIndex:0];
    alertText.keyboardType = UIKeyboardTypeNumberPad;
    alertText.placeholder = @"Pin";
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(controlTextDidChange:)
                                                 name:UITextFieldTextDidChangeNotification object:alertText];
    [_alert show];
    [_alert release];
    [[NSNotificationCenter defaultCenter] removeObserver:UITextFieldTextDidChangeNotification];
}


- (void)controlTextDidChange:(NSNotification *)notification {
    {
        NSString *pin = [[NSUserDefaults standardUserDefaults] stringForKey:@"Pin"];
        if ([notification object] == alertText)
        {
            if (alertText.text.length == pin.length)
            {
                if(counter != 0)
                {

                    if([alertText.text isEqualToString:pin])
                    {
                            [_alert dismissWithClickedButtonIndex:0 animated:NO];
                            [self.tableViewController openSettings];
                            counter = 3;
                    }
                    else
                    {
                            counter--;
                            [_alert dismissWithClickedButtonIndex:0 animated:NO];
                            [self showAlert:@""];

                    }
                }
                else
                {
                    [_alert dismissWithClickedButtonIndex:0 animated:NO];
                    [[NSUserDefaults standardUserDefaults] setObject:NULL
                                                              forKey:@"Telephone"];
                    [[NSUserDefaults standardUserDefaults] setObject:NULL
                                                              forKey:@"Pin"];
                    [[NSUserDefaults standardUserDefaults] synchronize];
                    UIAlertView *av = [[UIAlertView alloc] initWithTitle:@"" message:AMLocalizedString(@"EraseData", nil) delegate:nil cancelButtonTitle:AMLocalizedString(@"Ok", nil) otherButtonTitles:nil];
                    counter = 3;
                    [av show];
                    [av release];
                }

            }
        }
    }

}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    NSString *pincheck = [[NSUserDefaults standardUserDefaults] stringForKey:@"pinCheck"];
    if (buttonIndex == 0)
    {
        if(pincheck.intValue == 1)
        {
           NSLog(@"app kill");
            exit(0);
        }
        else
        {
            NSLog(@"dismiss");
        }
    }

}
@end

Here is where i initialize and use this class.

            case 5:
            NSLog(@"Add remove");
            if (pincheck != NULL && pin != NULL){
                if([pincheck isEqualToString:@"0"])
                {

                    AlertPassword *alert = [AlertPassword alloc];
                    alert.tableViewController = self;
                    NSString *msg = @"Enter your pin code to access:";
                    [alert showAlert:msg];
                //    [alert release];

                }
                break;
            }
            else
            {
                NSLog(@"Is null");
                [Menu load2View:self];
            }
            break;

I though maybe it was because i do not release alert. But adding [alert release]; Made to have EXC_BAD_ACCESS directly after the user tries to enter something. Without [alert release]; it works. But sometimes it craches with EXC_BAD_ACCESS

Also sometimes it gets

2012-11-08 12:11:27.451 kodinisRaktas[2485:19d03] *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[__NSMallocBlock__ dismissWithClickedButtonIndex:animated:]: unrecognized selector sent to instance 0x947aae0'

But I also have no idea why this happends

Please help, I'm pretty new to objective-c and ios, and I have no idea how to get rid of this, I guess someone with a bit of experience will see whats wrong in my code.

I'v just saw, that EXC_BAD_ACCESS or unrecognized selector throws if you push cancel for 4-5 times or more, and then try to type something.

4

4 回答 4

1

EXC_BAD_ACCESS is mostly due to bad memory handling. The alert has most likely become an zombie... I would have the alert as a property with strong/retain. You should hold on to it while displaying. Not release after "show".

When you set up the first you can do like this

_alert = [[UIAlertView alloc] initWithTitle:@"Security" message:msg delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles: nil]; // retain count: 1

Note calling "show" will also retain it, but that does not change the fact that you need to too.

[_alert show]; // retain count: 2

Wait for the delegate callback and release it.

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
    [_alert release], _alert = nil; // retain count in next run will be 0
}

Tip: It may be easier to handle if you use UIAlertView combined with blocks. http://gkoreman.com/blog/2011/02/15/uialertview-with-blocks/

于 2012-11-08T10:14:45.317 回答
0

I don't see where you initialize alert, anyway I suppose it's a class field, so retain it.If it's not a class instance variable, make it be so, this way you will always have a pointer to it.

[__NSMallocBlock__ dismissWithClickedButtonIndex:animated:]

You are sending this message to a raw malloc block, so probably alert has been released and points to a memory used for something else, something that's not an objc object.
Try to retain alert and see what happens.

于 2012-11-08T10:20:28.433 回答
0

May be you are passing wrong values to this "dismissWithClickedButtonIndex:animated:" method which is not recognizing the value signature please do a double check for that;

于 2012-11-08T10:26:08.723 回答
0

the excepted answer does make sense and is likely the cause

but what is this? [NSNotificationCenter defaultCenter] removeObserver:UITextFieldTextDidChangeNotification];

于 2012-11-08T18:33:02.267 回答