views:

43

answers:

3

A UIAlertView is displayed if an error occurs. But in the meantime the view on which the UIAlertView were called has been dismissed (and therefore released). If the user clicks on OK the app crashes because a message to a released instance is sent. This will cause your app crashing:

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 the UIAlertView is an independent unit. But it seems it isn't. Is there a way how I could avoid the app crashing (except not dismissing the view)?

A: 

Make sure you are implementing the UIAlertViewDelegate protocol. If you don't care about when the alert is dismissed just init with delegate as nil.

UIAlertView *alertView = [[UIAlertView alloc] initWithTitle:@"test" message:@"test" delegate:nil cancelButtonTitle:@"OK" otherButtonTitles:nil];
aegzorz
I have implemented the `UIAlertViewDelegate` protocol extra for this alert. It seems there is no other way than providing only a "OK" button and set the delegate to nil. I'll give it a try.
testing
A: 

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

delegate:self

Delegates are not retained, like an object added to an array, or a subview would be. So in your case, when you call:

[self.navigationController popViewControllerAnimated:YES];

self is most likely being released, and when the the user dismisses the alert, self is called, but has been dealloc'd so it no longer exists.

An easy way to check this is to put a logger statement, like NSLog(@"I'm gone"); in self's dealloc method, if it's ran, then you know your self isn't around anymore, and any messages sent to it will cause a crash.

SooDesuNe
Nice explanation. But what can I do against this?
testing
You have two choices, 1) pick a different delegate, or 2) have `self` retained by some other object (i.e. from other object [the-reference-to-what-were-calling-self retain]) Without knowing what you are doing in the delegate methods it's hard to say which is best. If you aren't using delegate methods, the have `nil` be the delegate
SooDesuNe
A: 

If the UIAlertView object is to be usable from anywhere in the app, not just on the current view, then retain it inside something that is available from anywhere in the app, either some persistant root view controller under the entire possible view stack, or the app delegate.

Added:

This top level object can also retain the alert view's delegate until after it's done being needed (after alert view dismissal).

hotpaw2
The UIAlertView is retained when you call show on it.
aegzorz
@aegzorz : retained by what?
hotpaw2
The more important question is who retains the alert view delegate? That needs to be persistant.
hotpaw2
Retained by the UIWindow that show puts it in. Yes, the alert view delegate should still be around when the alert view dismisses or be set to nil when the delegate is released.
aegzorz
I also thought about this. But this a little too complicated for this special case I think. This only happens if the user makes an action twice, where one of this action fails because of the little time for completion. In no other case I would need this.
testing