0

I have 2 view controllers, ViewController 1(VC1) and 2(VC2). In VC2 I have a back and done button. On clicking back button it goes directly to VC1 and on done it makes an api call and when it gets a response it shows an alert view and clicking ok goes back to VC1. Now when I make a api call a loading bar shows up and disappears when I get response and shows the AlertView. But if during that fraction of second when the loading disappears and AlertView is going to be popped up if I click on back and the view changes to VC1, the alert appears on VC1 and results in a crash.

This is a rare case as no user will purposely try for it but I was wondering if that crash can be managed without disabling the back button. I think there can be other instance such cases like if we are making an asynchronous calls and if the user is allowed to use UI while waiting for response and if any error alert that was suppose to show on one ViewController shows up in another may result in crash since the delegate that alert is referring to is that of the previous view controller. So is there any way to handle this kind of crash efficiently?

//Alert View sample
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:[[message objectAtIndex:1] capitalizedString] message:[message objectAtIndex:0] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil] ;
[alert setTag:701];
[alert show];

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex
{
    if ([alertView tag] == 701)
        if (buttonIndex == 0)
        {
            [self.navigationController popViewControllerAnimated:YES];
        }


}
Robert Karl
  • 7,598
  • 6
  • 38
  • 61
Francis F
  • 3,157
  • 3
  • 41
  • 79

1 Answers1

1

The proper way to fix this problem is to use an instance variable to keep a reference to the alert view.

This instance variable should be set to nil in the alertView:didDismissWithButtonIndex: delegate method.

In the view controller's dealloc method, you call dismissWithClickedButtonIndex:animated: if the instance variable is still set.

Assume _alertView is the instance variable.

Create the alert:

_alertView = [[UIAlertView alloc] initWithTitle:[[message objectAtIndex:1] capitalizedString] message:[message objectAtIndex:0] delegate:self cancelButtonTitle:@"OK" otherButtonTitles:nil] ;
[_alertView setTag:701];
[_alertView show];

Update your existing alertView:clickedButtonAtIndex: method:

- (void)alertView:(UIAlertView *)alertView clickedButtonAtIndex:(NSInteger)buttonIndex {
    if ([alertView tag] == 701) {
         _alertView.delegate = nil;            
         _alertView = nil;
        if (buttonIndex == 0) {
            [self.navigationController popViewControllerAnimated:YES];
        }
    }
}

Add:

- (void)alertView:(UIAlertView *)alertView didDismissWithButtonIndex:(NSInteger)buttonIndex {
    _alertView = nil;
}

Add:

- (void)dealloc {
    if (_alertView) {
        _alertView.delegate = nil;
        [_alertView dismissWithClickedButtonIndex:_alertView.cancelButtonIndex animated:NO];
        _alertView = nil;
    }
}
Francis F
  • 3,157
  • 3
  • 41
  • 79
rmaddy
  • 314,917
  • 42
  • 532
  • 579
  • This work for issue but causing crash for normal flow, that is when I click done and click ok on alert goes back and then crashes. – Francis F May 07 '14 at 06:07
  • Did you make the change to the `clickedButtonAtIndex:` method as I showed? – rmaddy May 07 '14 at 06:09
  • You may also need to add the line `_alertView.delegate = nil;` to your `clickedButtonAtIndex:` method (just before calling `_alertView = nil;`). – rmaddy May 07 '14 at 06:16
  • Ya I copy pasted your code. I tried the breakpoint inside dealloc, the _alertView is nil and it doesnt goes in but still crashes with EXC_BAD_ACCESS, commenting the dealloc code works fine. – Francis F May 07 '14 at 06:18
  • This is how I declared the alertView interface ViewController () {UIAlertView * _alertView;} end implementation ViewController .... – Francis F May 07 '14 at 06:19
  • Did you see my previous comment about the additional change to `clickedButtonAtIndex:`? – rmaddy May 07 '14 at 06:19
  • Ok, thats seems to work, one more doubt, why did u use dealloc, we can do this also in viewDidDisappear. Any specific reason? – Francis F May 07 '14 at 06:26
  • Since `viewDidAppear` can be called for different reasons, I prefer to use `dealloc` for this kind of cleanup. But either should work. – rmaddy May 07 '14 at 14:45
  • @CrimsonChris Please add your comment to the question, not my answer. – rmaddy May 07 '14 at 15:15