UIPopoverController dealloc getting called—ARC environment
Asked Answered
C

2

19

While displaying a popover controller for a second time (after dismissing it and then re-displaying it), I get the following error:

Terminating app due to uncaught exception 'NSGenericException', reason: '-[UIPopoverController dealloc] reached while popover is still visible.'

The stack trace is only a bunch of hex and the SIGABRT happens at UIApplicationMain every time. Here's the code that the button triggers:

- (IBAction)createNewScore:(id)sender {
    if (self.pc)
        if (self.pc.popoverVisible)
            return;
        else
        // Breakpoint is hit here—crashes after this line
            [self.pc presentPopoverFromBarButtonItem:(UIBarButtonItem *)sender permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
    NGDocumentInfoViewController *documentInfoVC = [[NGDocumentInfoViewController alloc] initWithBlankDocumentTargetInManagedObjectContext:self.context];
    UINavigationController *navc = [[UINavigationController alloc] initWithRootViewController:documentInfoVC];
    UIBarButtonItem *doneButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:@selector(doneCreatingNewScore:)];
    UIBarButtonItem *cancelButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemCancel target:self action:@selector(cancelCreatingNewScore:)];
    navc.navigationBar.topItem.leftBarButtonItem = doneButton;
    navc.navigationBar.topItem.rightBarButtonItem = cancelButton;
    CGSize popoverSize = CGSizeMake(documentInfoVC.view.bounds.size.width, documentInfoVC.view.bounds.size.height);
    documentInfoVC.contentSizeForViewInPopover = popoverSize;
    UIPopoverController *popover = [[UIPopoverController alloc] initWithContentViewController:navc];
    popover.delegate = self;
    self.pc = popover;
    [popover presentPopoverFromBarButtonItem:(UIBarButtonItem *)sender permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}

I'd like to just retain the popover which would fix the issue, but this is an ARC environment so I don't have retain. Is there a way for me to fix the error (without turning off ARC for the file and having to manually do the memory for the entire file)?

Edit: The popover is stored as an ivar:

@property (strong) UIPopoverController *pc;

Does anyone have a solution for this problem (maybe an ARC override)? I'll file a BR as CodaFi suggests, but a solution would still be nice, as this is a roadblock in a major project. If this is not possible, then I suppose I'll roll my own.

Chronometer answered 28/10, 2011 at 21:32 Comment(6)
Can you set a symbolic breakpoint on -[UIPopoverController dealloc] (using the + at the bottom of the breakpoints navigator in Xcode) and see where it stops in the debugger? Maybe the stack trace there can give some insights as to what's freeing your popover.Ophidian
The breakpoint isn't being explicitly hit. It's pausing happening at UIApplcationMain before crashing, which seems to indicate that it's at least partially related to the run loop. I'm tempted to call it a bug with ARC since it's so low-level. Full stack trace: bit.ly/rTf7f0Chronometer
Is createNewScore executed on the main thread?Underprivileged
Yes, no explicit threading going on anywhere here. If there are threads involved they'd be in Apple's code, not mine.Chronometer
Just a little word of warning, UIPopover as a whole is crap compared to the rest of ios implementations. File your bug report, but from what I've heard from people who went to WWDC, apple isn't gonna fix popovers anytime soon.Bartolomeo
You may check this post #2868209Dosage
L
18

I have run into the same problem and fixed it by retaining the popover controller in a strong instance variable as suggested AND explicitly dismissing it before resetting the property with the new popover controller allocated in in the second run of the action. In your example, you should add something like this:

- (IBAction)createNewScore:(id)sender {
    if (self.pc) {
         [self.pc dismissPopoverAnimated:YES];
    }
Limeade answered 22/1, 2012 at 10:52 Comment(1)
Just creating the instance variable worked for me. Touching outside of the popover also dismisses it later on in case you don't want to use a button.Scorper
L
3

If your popover is stored as strong reference, it can't be deallocated. The only possibility when it can be deallocated is in the situation when the object containing the strong reference (self in your example) is also deallocated.

I think the important question is what are you doing with your views when the popover is visible.

If you have already checked this, than it must be a framework bug.

Lanellelanette answered 8/11, 2011 at 13:50 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.