0

I'm getting the (apparently common) error [UIPopoverController dealloc] reached while popover is still visible. when I try to show a popover controller in my iPad app.

There are a ton of questions on here, but my problem appears to be different. First of all, I am maintaining a strong reference to the popover controller via a property on my parent view controller:

@property (strong, nonatomic) UIPopoverController* passcodePopover;

Here is my code that actually presents the popover (note I am using the third-party BZPasscodeViewController):

- (IBAction)adminConfig:(id)sender {
    self.passView = [[BZPasscodeViewController alloc] init];
    self.passView.title = @"Kiosk Administration";
    self.passView.text = @"Enter passcode:"; // TODO: localize
    self.passView.handler = ^(NSString *enteredPasscode, NSString **text, NSString **detailText, BOOL *detailTextHighlighted) {
        NSLog( @"password handler!" );
        return BZPasscodeViewControllerResultDone;
    };
    UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:self.passView];
    self.passView.contentSizeForViewInPopover = [BZPasscodeViewController defaultContentSizeForView];
    self.passView.modalInPopover = YES;
    UIPopoverController* uipc = [[UIPopoverController alloc] initWithContentViewController:navigationController];
    self.passcodePopover = uipc;
    [self.passcodePopover bz_presentPopoverInWindow:self.view.window animated:YES];
}

Now the bizarre thing is it appears to be crashing on the call to set the property as can be seen in this stack trace snippet:

0   CoreFoundation                      0x01d2802e __exceptionPreprocess + 206
1   libobjc.A.dylib                     0x01165e7e objc_exception_throw + 44
2   CoreFoundation                      0x01d27deb +[NSException raise:format:] + 139
3   UIKit                               0x00573bf2 -[UIPopoverController dealloc] + 86
4   libobjc.A.dylib                     0x011799ff -[NSObject release] + 47
5   libobjc.A.dylib                     0x011780d5 objc_release + 69
6   libobjc.A.dylib                     0x01178fda objc_storeStrong + 39
7   Kiosk                               0x00047d59 -[SplashViewController setPasscodePopover:] + 57
8   Kiosk                               0x00047ad2 -[SplashViewController adminConfig:] + 802
...

However, the popover is appearing in the simulator immediately before the app crashes, so it's clearly getting past the present call. There's apparently some other implicit call to setPasscodePopover: happening somewhere.

If it provides any insight, the method above is being triggered by a gesture recognizer.

devios1
  • 36,899
  • 45
  • 162
  • 260
  • 1
    Is it possible that `self.passcodePopover` is not already nil when you assign `uipc` to it? And that it is in fact referring to a popover controller that is still visible? Put `NSLog("old popover controller = %@", self.passcodePopover)` in your method before `self.passcodePopover = uipc`, or check it with a breakpoint. – rob mayoff Jun 27 '13 at 23:26
  • Aha! I think you've found something. Turns out, as I was expecting, self.passcodePopover is null *the first time*. But apparently my method is being called more than once! Probably by the gesture recognizer. I think you've solved it. :) – devios1 Jun 27 '13 at 23:33

1 Answers1

1

self.passcodePopover is not nil when you are assigning uipc to it. It already points to an on-screen popover controller. When you assign uipc to self.passcodePopover, that releases the old popover controller, which then gets deallocated while its view is still visible.

You need to figure out when you want to dismiss the old popover. You could simply dismiss it just before reassignment:

[self.passcodePopover dismissPopoverAnimated:YES];
self.passcodePopover = uipc;

Note that it's safe to send dismissPopoverAnimated: to nil (it has no effect), so you don't even have to check it first.

rob mayoff
  • 375,296
  • 67
  • 796
  • 848
  • In my case, the gesture recognizer was simply calling the method twice in succession, so I don't need to dismiss the previous one. All I needed was to check if it was already set and if so, return. – devios1 Jun 27 '13 at 23:39