UIAlertView EXC_BAD_ACCESS error - objective-c

I cannot figure out why I keep getting an EXC_BAD_ACCESS error on the line below in the action sheet method:
[[UIApplication sharedApplication]openURL:[NSURL URLWithString:numberFinal]];
I added my code, but I just don't see why its being over released.
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
number = [[results objectAtIndex:indexPath.row]objectForKey:#"phone"];
number = [number stringByReplacingOccurrencesOfString:#"-" withString:#""];
numberFinal = [NSString stringWithFormat:#"tel:%#",number];
//tel:1234567890
NSLog(#"NUMBER:%#",numberFinal);
[tableView deselectRowAtIndexPath:indexPath animated:YES];
UIAlertView *alert2 = [[[UIAlertView alloc]initWithTitle:#"Call" message:#"Call This Person?" delegate:self cancelButtonTitle:#"NO" otherButtonTitles:#"YES", nil]autorelease];
alert2.tag = kAlertViewTwo;
[alert2 show];
// [alert2 release];
}
- (void)alertView:(UIAlertView *)actionSheet clickedButtonAtIndex:(NSInteger)buttonIndex {
// the user clicked one of the OK/Cancel buttons
if(actionSheet.tag == kAlertViewOne) {
if (buttonIndex == 0)
{
}else{
}
}
else if(actionSheet.tag == kAlertViewTwo) {
if (buttonIndex == 0)
{
//ok button clicked - close alert
}
else
{
[[UIApplication sharedApplication]openURL:[NSURL URLWithString:numberFinal]];
}
}
}

Try do an NSLog before the line and print numberFinal to see if it allocated ok.
Make sure your class is a UIAlertView Delegate
Try the same line of code in another function to see if it causes the same issue. It might be because you are accessing sharedApplication from within the UIAlertView click event.
Hope that helps :)

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.

UIAlertView buttonIndex not working

I guess I'm missing something obvious. I have UIAlertView to get app review but I can't get the buttons to do anything. I've called the UIAlertViewDelegate in my.h, I also have anther UIAlertview which is just on an IBAction btn and that works fine although it just had cancel btn.
I tried giving alert.tag = 1 but that never made any difference so I commented out my first UIAlertview, so I just have one alert, still no joy. I guess I am missing something simple.
I've also tried alertview.cancelButtonIndex or alertview.firstOtherButtonIndex instead of 0
-(void) alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
if (buttonIndex == 0) {
NSLog(#"index 0 ");
}
else if (buttonIndex == 1) {
NSLog(#"index 1 ");
[[UIApplication sharedApplication] openURL:[NSURL URLWithString:#"www.google.com"]];
NSUserDefaults *rateApp = [NSUserDefaults standardUserDefaults];
NSInteger appLaunch = [ rateApp integerForKey:#"appLaunch"];
appLaunch = 0 ;
[rateApp setInteger: appLaunch forKey:#"appLaunch"];
}
else if (buttonIndex == 2) {
NSLog(#"index 2 ");
}
}
- (void)viewDidLoad
{
[super viewDidLoad];
//rate app appLaunch == 5 || appLaunch ==10
NSUserDefaults *rateApp = [NSUserDefaults standardUserDefaults];
NSInteger appLaunch = [ rateApp integerForKey:#"appLaunch"];
if (appLaunch == 1 ) {
UIAlertView *alert = [[UIAlertView alloc]initWithTitle:#"Like this app ?" message:#"Why not rate at the app store" delegate:nil cancelButtonTitle:#"No thanks" otherButtonTitles:#"Yes",#"Remind me later", nil];
// alert.tag = 1;
[alert show];
}
Thanks for any help.
AlertView's delegate should be self instead of nil, if you want to invoke its delegate method.
Use this Code :
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Like this app ?"
message:#"Why not rate at the app store"
delegate:self
cancelButtonTitle:#"No thanks"
otherButtonTitles:#"Yes",#"Remind me later", nil];

Alert before deleting UITableView cell - (UIAlertController) Swift or Objective-C

I want to delete a Table View cell, but before that action happens I want to give the user an alertview. I got this:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Warning"
message:#"Are you sure?"
delegate:self
cancelButtonTitle:#"NO"
otherButtonTitles:#"YES", nil];
[alert show];
[self.array removeObjectAtIndex:indexPath.row];//or something similar to this based on your data source array structure
[tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:indexPath] withRowAnimation:UITableViewRowAnimationFade];
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"Nee"])
{
NSLog(#"Nothing to do here");
}
else if([title isEqualToString:#"Ja"])
{
NSLog(#"Delete the cell");
}
}
But now when I swipe to right on the cell and the delete button appears I got no AlertView. I only get the AlertView when I press on the delete button. When I press on the delete button the message appears but the cell is already been deleted.
How to make this work? So there is an AlertView when I swipe.
Regarding the sequence, everything is fine. commitEditingStyle will be called only when the delete button was pressed already. The point is that you are actually removing the object before the alert is responded to. Change it to this:
Add this to the .m file before #implementation:
#interface PutYourViewControllerClassNameHere
#property (strong, nonatomic) NSIndexPath *indexPathToBeDeleted;
#end
And then:
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
self.indexPathToBeDeleted = indexPath;
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Warning"
message:#"Are you sure?"
delegate:self
cancelButtonTitle:#"NO"
otherButtonTitles:#"YES", nil];
[alert show];
// do not delete it here. So far the alter has not even been shown yet. It will not been shown to the user before this current method is finished.
}
}
- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
// This method is invoked in response to the user's action. The altert view is about to disappear (or has been disappeard already - I am not sure)
NSString *title = [alertView buttonTitleAtIndex:buttonIndex];
if([title isEqualToString:#"NO"])
{
NSLog(#"Nothing to do here");
}
else if([title isEqualToString:#"YES"])
{
NSLog(#"Delete the cell");
[self.array removeObjectAtIndex:[self.indexPathToBeDeleted row]];
[self.tableView deleteRowsAtIndexPaths:[NSArray arrayWithObject:self.indexPathToBeDeleted] withRowAnimation:UITableViewRowAnimationFade];
}
}
Edit: This should compile, despite minor syntax errors probably.
General assupmtion: You are dealing with one section only. At least only with one section within deletions are possible.
iOS 8 +
iOS 8 introduced UIAlertController. This allows you to write your delete and cancel code in completion blocks instead of in delegate methods (as per -clickedButtonAtIndex of the old UIAlertView).
Swift 3
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
if editingStyle == .delete {
let alertController = UIAlertController(title: "Warning", message: "Are you sure?", preferredStyle: .alert)
let deleteAction = UIAlertAction(title: "Delete", style: .destructive, handler: { (action) in
self.tableView.deleteRows(at: [indexPath], with: .fade)
})
alertController.addAction(deleteAction)
let cancelAction = UIAlertAction(title: "Cancel", style: .default, handler: nil)
alertController.addAction(cancelAction)
present(alertController, animated: true, completion: nil)
}
}
Objective-C
- (void)tableView:(UITableView *)tableView commitEditingStyle:(UITableViewCellEditingStyle)editingStyle forRowAtIndexPath:(NSIndexPath *)indexPath {
if (editingStyle == UITableViewCellEditingStyleDelete) {
UIAlertController *alertController = [UIAlertController alertControllerWithTitle:#"Warning" message:#"Are you sure?" preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction *deleteAction = [UIAlertAction actionWithTitle:#"Delete" style:UIAlertActionStyleDestructive handler:^(UIAlertAction * _Nonnull action) {
[self.tableView deleteRowsAtIndexPaths:#[indexPath] withRowAnimation:UITableViewRowAnimationFade];
}];
[alertController addAction:deleteAction];
UIAlertAction *cancelAction = [UIAlertAction actionWithTitle:#"Cancel" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
NSLog(#"Don't do anything");
}];
[alertController addAction:cancelAction];
[self presentViewController:alertController animated:YES completion:nil];
}
}
Youre calling the Alert when the deleting action is already taking place....
Put it in:
-(void)tableView:(UITableView*)tableView willBeginEditingRowAtIndexPath:(NSIndexPath *)indexPath
{
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Waarschuwing!"
message:#"Weet je zeker dat je het vak: lalaal wilt verwijderen?"
delegate:self
cancelButtonTitle:#"Nee"
otherButtonTitles:#"Ja", nil];
[alert show];
}
That will call the alert when the cell is swiped and before the button is pressed.
iOS 9.0 and Swift 2.3
func tableView(tableView: UITableView, commitEditingStyle editingStyle: UITableViewCellEditingStyle, forRowAtIndexPath indexPath: NSIndexPath) {
if editingStyle == .Delete {
let alertController = UIAlertController(title: "Warning!", message: "You're about to delete this stuff right meow.", preferredStyle: .Alert)
let delete = UIAlertAction(title: "Do it.", style: .Destructive, handler: { action in
tableView.beginUpdates()
//delete from your datasource!
tableView.deleteRowsAtIndexPaths([indexPath], withRowAnimation: .Fade)
tableView.endUpdates()
})
let cancel = UIAlertAction(title: "Cancel", style: .Cancel, handler: { action in
//this is optional, it makes the delete button go away on the cell
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .Automatic)
})
alertController.addAction(delete)
alertController.addAction(cancel)
presentViewController(alertController, animated: true, completion: nil)
}
}

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];