Click UIAlertView app if the application is rejected

A UIAlertView displayed if an error occurs. But in the meantime, the view that UIAlertView was called on was fired (and therefore released). If the user clicks the OK button, the application crashes due to sending a message to the released instance. This will crash your application:

 UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"test" message:@"test" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; [alertView show]; [alertView release]; alertView = nil; [self.navigationController popViewControllerAnimated:YES]; 

I thought UIAlertView is an independent module. But this does not seem to be the case. Is there a way that I could avoid crashing the application (except that I didn't reject the view)?

+4
source share
6 answers

The delegate is called when the UIAlertView rejected, so in your case:

 delegate:self 

Delegates are not saved as an object added to an array, or a preview. Therefore, in your case, when you call:

 [self.navigationController popViewControllerAnimated:YES]; 

self is likely to be issued, and when the user rejects the warning, self is called, but it was disabled, so it no longer exists.

An easy way to check this is to put a logger statement, such as NSLog(@"I'm gone"); in self dealloc , if it is running, then you know that your self no longer exists, and all sent messages will cause this to fail.

+10
source

Make the UIAlertView a saved property of the controller of your view so that you can reference it in your dealloc, and then set the warning view delegate to zero when the view manager is free.

Be sure to correctly release the saved warning as soon as it is rejected, and to dealloc.

For instance:

 @interface MyViewController : UIViewController <UIAlertViewDelegate> { UIAlertView *alertView; } @property (nonatomic, retain) UIAlertView *alertView; @implementation MyViewController @synthesize alertView; - (void)showAlert { if (alertView) { // if for some reason the code can trigger more alertviews before // the user has dismissed prior alerts, make sure we only let one of // them actually keep us as a delegate just to keep things simple // and manageable. if you really need to be able to issue multiple // alert views and be able to handle their delegate callbacks, // you'll have to keep them in an array! [alertView setDelegate:nil]; self.alertView = nil; } self.alertView = [[[UIAlertView alloc] initWithTitle:@"Error" message:@"Something went wrong" delegate:self cancelButtonTitle:@"Cancel" otherButtonTitles:@"Retry",nil] autorelease]; [alertView show]; } - (void)alertView:(UIAlertView *)alertViewParam didDismissWithButtonIndex:(NSInteger)buttonIndex { self.alertView = nil; // release it // do something... } - (void)dealloc { [alertView setDelegate:nil]; // this prevents the crash in the event that the alertview is still showing. self.alertView = nil; // release it [super dealloc]; } 

The disadvantage here is that you cannot handle the alert type callback when the user rejects it. However, since your controller has already gone / released, apparently you don't need to. If you do this, you must set the alert delegate to what will persist.

+5
source

If the UIAlertView object is to be used anywhere in the application, and not just in the current view, save it inside what is available anywhere in the application, or any stable root view controller under all possible viewing stacks, or the application delegate.

Added:

This top-level object can also save the alert presentation delegate until it is needed (after leaving the warning).

+1
source

(People might think that I'm late for years answering this question, but it might help someone else)

I assume that your problem lies in where, when the view controller appears, you display the warning view and at the same time try to translate the user back into the view. I would recommend you follow a hierarchical approach here:

First of all, declare your warning as a global object, i.e.

 @property(nonatomic,retain) UIAlertView *sampleAlert; 

Now write your warning display code wherever it appears, say, for example:

 -(IBAction)buttonClicked:(id)sender { self.sampleAlert = [[UIAlertView alloc] initWithTitle:@"test" message:@"test" delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil]; [sampleAlert show]; [sampleAlert release]; } 

Finally, try switching to the desired user when the "Ok" button is pressed, i.e. you need to use the alertView didDismissWithButtonIndex method, i.e.

 - (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex { if(alertView == sampleAlert) { [self.navigationController popViewControllerAnimated:YES]; } } 

Please note that if you have a warning with several buttons, you also need to check the button index for distinctive actions, i.e. check with

 if(alertView == sampleAlert && buttonIndex == 0) { //Do your stuff } else { //Do something else } 

This will definitely avoid the application crash, thanks :)

+1
source

An easier way that worked for me was to hold all kinds of alerts in the array and when the parent view is freed, enumerate the array of alertViews and set the delegate to zero. This ensures that the touch event is ignored and the application functions.

 // ARC world @property (strong, nonatomic) NSMutableArray *alertViews; - (void)dealloc { [self.alertViews makeObjectsPerformSelector:@selector(setDelegate:) withObject:nil]; } 
+1
source

Make sure you are using the UIAlertViewDelegate protocol. If you are not interested when the warning is rejected, just init with the delegate as nil .

 UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"test" message:@"test" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil]; 
-2
source

All Articles