The iOS app crashed right after clicking the button on a UIAlertview - objective-c

I tried to dial a number with the phone app after the user click on a button on a UIAlertview. The phone app did open, but the original app crashed right after clicking the button on the UIAlertview. Does anyone one know the reason? I did try to make sure I released everything that should be released. Thanks! Below is the code:
-(IBAction)dialButtonPressed:(UIButton *)numberButton
{
if ([company isEqualToString:#"Not Found"]==true){
message = [[UIAlertView alloc] initWithTitle:#"Sorry"
message:#"No replace number found. Would you like to dial anyway?"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
message.tag = 0;
if(phoneLinkString)
{
[phoneLinkString release];
phoneLinkString = nil;
}
[message show];
[message autorelease];
phoneLinkString = [[NSString stringWithFormat:#"tel:%#",replace]retain];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
[self release];
message = nil;
if(message.tag == 0 && buttonIndex == 1){
NSURL *phoneLinkURL = [NSURL URLWithString:phoneLinkString];
[[UIApplication sharedApplication] openURL:phoneLinkURL];
}
- (void)dealloc {
[phoneNumberString release];
[phoneNumberLabel release];
[self release];
[message release];
[super dealloc];
}
The newest code
-(IBAction)dialButtonPressed:(UIButton *)numberButton
{
if ([company isEqualToString:#"Not Found"]==true){
message = [[UIAlertView alloc] initWithTitle:#"Sorry"
message:#"No replace number found. Would you like to dial anyway?"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
message.tag = 1;
if(phoneLinkString)
{
[phoneLinkString release];
phoneLinkString = nil;
}
[message show];
[message autorelease];
phoneLinkString = [[NSString stringWithFormat:#"tel:%#",replace]retain];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(message.tag == 1 && buttonIndex == 1){
NSURL *phoneLinkURL = [NSURL URLWithString:phoneLinkString];
[[UIApplication sharedApplication] openURL:phoneLinkURL];
message = nil;
}
}
- (void)dealloc {
[phoneNumberString release];
[phoneNumberLabel release];
[super dealloc];
}
but it still crashed after clicking the button on the UIAlertview. The error is 0x3beb85b0: ldr r3, [r4, #8] EXC_BAD_ACCESS (code=1, address=0x7269634f) Any help would be appreciated. Thanks!

The problem might be that you set your alert to nil before your if statement. Try putting it after.

The crash is happening due to this code. [self release];.
When you call self release the view in which the alert is displayed will released and deallocated, not the alertView. That's the cause of crash.
You are already releasing the alertViews memory in the dialButtonPressed: method using [message autorelease];
So no need to release the alertView again in clickedButtonAtIndex. So change the method like:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if(alertView.tag == 0 && buttonIndex == 1)
{
NSURL *phoneLinkURL = [NSURL URLWithString:phoneLinkString];
[[UIApplication sharedApplication] openURL:phoneLinkURL];
}
message = nil;
}

Your crash is being caused by poor memory management. The primary issue is calling [self release]. It's a pretty rare case that this is appropriate.
Another issue is your attempt to check the message.tag right after setting message to nil. Calling the tag property on a nil object will always result in a value of 0.
Your dealloc method is all wrong. Don't call [self release]. Don't call [message release] since you autoreleased it when you showed it.
BTW - never use a tag of 0. This is the default. If you want to use the tag, always use a non-zero value so you can distinguish the value from the default.

Related

Two Alertviews on one view [duplicate]

This question already has answers here:
Two Alert Views in One View Controller - buttonIndex Response
(4 answers)
Closed 7 years ago.
EDIT:
Problem Solved ==> Simply giving a tag solved the problem.
I have the following problem:
On a view I have two UIalertviews:
NSString *message = [NSString stringWithFormat:#"Users must enter this code to join the meeting: %#", meetingCode];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Meeting code"
message:message
delegate:self
cancelButtonTitle:#"OK"
otherButtonTitles:#"Copy to clipboard", nil];
[alert show];
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex == [alertView cancelButtonIndex])
{
NSLog(#"Code not copied");
}
else
{
UIPasteboard *pasteboard = [UIPasteboard generalPasteboard];
pasteboard.string = meetingCode;
NSLog(#"Code copied");
}
}
and this one:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
AgendaModel* agenda = _meeting.agenda[indexPath.row] ;
NSDictionary *dict = [[NSDictionary alloc] initWithObjectsAndKeys:agenda.id,#"id",agenda.name,#"name", nil];
NSString *message = [NSString stringWithFormat:#"Are you sure that you want to delete : %#?", agenda.name];
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Warning"
message:message
delegate:self
cancelButtonTitle:#"Close"
otherButtonTitles:#"Delete", nil];
[alert show];
NSString *delete_url = [NSString stringWithFormat:#"RestAgendas/delete.json"];
[_meeting.agenda removeObject:agenda];
[self.tableView deleteRowsAtIndexPaths:[NSMutableArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
[JSONAPI getWithPath:delete_url andParams:dict completion:^(id json, JSONModelError *err) {
NSLog(#"%#", json);
}];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(buttonIndex == [alertView cancelButtonIndex])
{
NSLog(#"Agenda Won't Be Deleted");
}
else
{
NSLog(#"Agenda Will Be Deleted");
}
}
Now is the problem that I got the error: Duplicate declaration of method 'alertView:clickedButtonAtIndex'
How can I fix this? I tried some stuff I found here but I still can't make it work. Can someone help me?
Yep, like you said, giving a tag allows you to have multiple UIAlertView in one single view.
Same goes for UIActionSheet or UIAlertController
for future reference, even though this is probably a duplicate, simply create your alert like usual and add
myAlert.tag = 123; //any number of your choice
and in alertView:clickedButtonAtIndex
you can find it using a switch or some if's
if (alertview.tag = 123){
// this is my alert
}else if(alertview.tag = 333){
// this is my other alert
}
For what it's worth, I suggest using else if and not just if to avoid the whole method to be read everytime, and order your if's by decreasing likeliness of being called.
Note you can also give tags to buttons, views, cells, labels, and just pretty much every outlet you can find.

Prevent from UIAlertView to repeat when click on tableViewCell

I'm kinda stuck with a stupid problem, in my app when a user press on a TableViewCell he can change some value in the server, before i am sending the information to server i want to show UIAlertView to the user to make sure he wants to do that.
so in didSelectRowAtIndexPath:
i wrote this
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Caution!" message:#"bla bla " delegate:self cancelButtonTitle:#"Cancel" otherButtonTitles:#"Ok", nil];
[alert show];
then its calls the UIAlertView method clickedButtonAtIndex:
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if (buttonIndex == 0) {
NSString *url = #"some url";
NSDictionary *paramerter = #{#"parameter":parameter};
[self.jsonHandler startParseWithParameters:paramerter andUrlAdress:url withCompletion:^(int errValue) {
if (errValue == 1) {
NSLog(#"ERROR");
}else if (errValue == 0){
[self AlertViewWithTitle:#"success" andMessage:#"success"];
}
}];
}
}
the problem is that the if (buttonIndex == 0) called for every cell and change them all!
and i get UIAlertView message for every cell in the tableView.
how can i prevent it?
EDIT
Ok the problem caused because i use the same buttonIndex for both UIAlertViews
i solved it using this:
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"buttonString"]){
//Do what ever you need
}
hope someone find it helpful.

How to deal with this NSString correctly with cocos2d?

I'm new with cocos2d so i've got a problem with my In-App Purchase Class Helper. I wrote game in Cocoa Touch and this class working perfectly, but i'm writing now the same game in Cocos2d and problem is with NSString.
Here are some snippets.
This method is called as first when i clicked some button. As you see completeIdentifier is simple string with bundleIdentifier and some string parameter. It's ok, in this place i can log this completeIdentifier.
- (void)prepareToPurchaseItemWithIdentifier:(NSString *)aIdentifier showAlertWithTitle:(NSString *)title description:(NSString *)description delegate:(id)aDelegate{
self.delegate = aDelegate;
identifier = aIdentifier;
completeIdentifier = [NSString stringWithFormat:#"%#.%#", [[NSBundle mainBundle] bundleIdentifier], aIdentifier];
askToPurchase = [[UIAlertView alloc] initWithTitle:title message:description delegate:self cancelButtonTitle:nil otherButtonTitles:#"Later", #"Yes", nil];
askToPurchase.delegate = self;
[askToPurchase show];
}
Next method is UIAlertViewDelegate method. Is called when i click YES on alertView from first method.
#pragma mark - UIAlertViewDelegate Methods
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
NSLog(#"%#", completeIdentifier);
if (alertView == askToPurchase) {
NSLog(#"[TSIAPHelper] Clicked YES. Prepare...");
if ([SKPaymentQueue canMakePayments]) {
NSLog(#"[TSIAPHelper] Prepare to purchase [%#].",completeIdentifier);
SKProductsRequest *request =[[SKProductsRequest alloc] initWithProductIdentifiers:
[NSSet setWithObject:completeIdentifier]];
request.delegate = self;
[request start];
pleaseWait = [[UIAlertView alloc] initWithTitle:#"Please wait..." message:#"" delegate:self cancelButtonTitle:nil otherButtonTitles:nil, nil];
UIActivityIndicatorView *activity = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhite];
[activity startAnimating];
[pleaseWait addSubview:activity];
activity.frame = CGRectMake(125, 50, 36, 36);
[pleaseWait show];
}
else {
NSLog(#"[TSIAPHelper] Purchase [FAILURE]. Prohibited by Parentar Control or something like that.");
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Prohibited." message:#"Parental Control is enabled, cannot make a purchase. Turn off and try again." delegate:self cancelButtonTitle:nil otherButtonTitles:#"Ok", nil];
[alert show];
}
}
}
The problem is: Whenever and anywhere i want to Log variable completeIdentifier i've got crash with selected line: 0x39e965d0: ldr r3, [r4, #8] but i don't know what's that mean. And this line is selected:
NSLog(#"%#", completeIdentifier);
How can i fix it? In Cocoa Touch is working perfectly. When i use cocos2d isn't.
I guess you aren't using ARC. In this case completeIdentifier will be autoreleased.
Cocos2d clears the autoreleasepool every frame, whereas in Cocoa this is not strictly defined but may still crash. You can fix this by retaining or copying the string.
completeIdentifier = [NSString stringWithFormat:#"%#.%#", [[NSBundle mainBundle] bundleIdentifier], aIdentifier];
completeIdenfitier = [completeIdentifier retain];

The iOS app crashed right after clicking on a UIAlertview [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
The iOS app crashed right after clicking the button on a UIAlertview
I tried to dial a number with the phone app after the user click on a button on a UIAlertview. The phone app did open, but the original app crashed right after clicking the button on the UIAlertview. Does anyone one know the reason? I did try to make sure I released everything that should be released. The error is 0x3beb85b0: ldr r3, [r4, #8] EXC_BAD_ACCESS (code=1, address=0x7269634f) Any help would be appreciated. Thanks! Below is the code:
-(IBAction)dialButtonPressed:(UIButton *)numberButton
{
if ([company isEqualToString:#"Not Found"]==true){
message = [[UIAlertView alloc] initWithTitle:#"Sorry"
message:#"No replace number found. Would you like to dial anyway?"
delegate:self
cancelButtonTitle:#"No"
otherButtonTitles:#"Yes", nil];
message.tag = 1;
if(phoneLinkString)
{
[phoneLinkString release];
phoneLinkString = nil;
}
[message show];
[message autorelease];
phoneLinkString = [[NSString stringWithFormat:#"tel:%#",replace]retain];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
if(message.tag == 1 && buttonIndex == 1){
NSURL *phoneLinkURL = [NSURL URLWithString:phoneLinkString];
[[UIApplication sharedApplication] openURL:phoneLinkURL];
message = nil;
}
}
- (void)dealloc {
[phoneNumberString release];
[phoneNumberLabel release];
[super dealloc];
}
Could you try didDismissWithButtonIndex instead of clickedButtonAtIndex. I am guessing let me know.
- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex;

iOS EXC_BAD_ACCESS error in class

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.
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/
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.
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;
the excepted answer does make sense and is likely the cause
but what is this?
[NSNotificationCenter defaultCenter] removeObserver:UITextFieldTextDidChangeNotification];