5
    UIPopoverController *historyPop = [[UIPopoverController alloc] initWithContentViewController:nav];
    [nav release];
    [historyPop setPopoverContentSize:CGSizeMake(400, 500)];
    [historyPop presentPopoverFromRect:CGRectMake(button.frame.origin.x, button.frame.origin.y, button.frame.size.width, 5) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionDown animated:YES];
    //[historyPop release];

This is my current code, however the Analyser says that the is probably a leak, which there is (as the release line is commented out). But if I uncomment the release line then the app crashes and says dealloc was reach on the popover while it is still visible, so when exactly should I be releasing the popover controller?

Jonathan.
  • 53,997
  • 54
  • 186
  • 290

2 Answers2

5

As mentioned in several places, the methods that present a popover (either from a rect, or from a toolbar button) do not retain the popover. So, your presenting view controller needs to hold a reference to it and release it at the appropriate time.

You can do this by setting the presenting view controller as the popover's delegate, as mentioned. A simpler, if slightly less memory-efficient, approach is to declare a retain property to hold the UIPopoverController. When you create the popover you assign it to the property, which retains it. If you later create another popover, it will release the previous popover when you reassign the property. Don't forget to release the property in the presenting view controller's dealloc method (as well as viewDidUnload).

This approach won't leak, and you don't need to deal with delegates. But, you will potentially keep a UIPopoverController object around longer than necessary. It's up to you to determine if that's a concern for your app.

Adam Milligan
  • 2,826
  • 19
  • 17
  • Setting the presenting view controller as the UIPopoverController's delegate doesn't retain the popover controller. The point of using the delegate is that you can appropriately release the popover controller when you receive the `popoverControllerDidDismissPopover:` call. So, doing both makes the most sense. – Jesse Rusak Jan 14 '11 at 01:40
  • 1
    It's bloody annoying that they don't retain when presenting, and it completely dismatches other similar methods (such as presenting modal views, adding subviews) – Jonathan. Apr 03 '11 at 16:26
  • Note: if you go the non-delegate route, you'll get a "[UIPopoverController dealloc] reached while popover is still visible" if the user dismisses the pop-over and immediately loads another pop-over - the first one takes time to get "non-visible" and will end up getting dealloc'd before it finishes that, causing a crash. – Jason Apr 05 '12 at 22:07
  • Can avoid that crash I mentioned by calling this before setting popover controller to new controller: if( self.popoverController.popoverVisible ) { [self.popoverController dismissPopoverAnimated:NO]; // prevents crash } – Jason Apr 05 '12 at 22:18
2

Try autoreleasing the popover: [historyPop autorelease]. presentPopoverFromRect does not retain the popover, so autorelease won't work here. You need to setup your class as a delegate of the popover controller, and release the popover in popoverControllerDidDismissPopover:.

bosmacs
  • 7,341
  • 4
  • 31
  • 31
  • 2
    Sorry, my mistake -- `presentPopoverFromRect` does not retain the popover, so autorelease won't work here. You need to setup your class as a delegate of the popover controller, and release the popover in `popoverControllerDidDismissPopover:`. See the second answer to this question: http://stackoverflow.com/questions/2867709/retain-release-pattern-for-uipopovercontroller-uiactionsheet-and-modal-view-con – bosmacs Dec 07 '10 at 19:39
  • probably worth editing your answer to include your comment, as anyone who reads the answer but not the comments will be misled – Brad Cupit Jan 13 '11 at 21:12