Retain/release pattern for UIPopoverController, UIActionSheet, and modal view controllers?
Asked Answered
P

2

14

I'm somewhat unclear on the object ownership patterns required for the following instances. When my UIViewController presents a popover controller, an action sheet, or another view controller as modal, am I required to hang onto a retained reference to that child controller until it's been dismissed?

In other words, do the following lines of code effectively "transfer" ownership, or not?

[aPopoverController presentPopoverFromBarButtonItem:someButtonItem permittedArrowDirections:UIPopoverArrowDirectionAny animated:NO];

[anActionSheet showFromBarButtonItem:someButtonItem animated:NO];

[aViewController presentModalViewController:someOtherViewController animated:YES];

Can someone point me to explicit documentation on this subject?

Philipps answered 19/5, 2010 at 16:59 Comment(0)
S
26

UIPopoverViewController has a slight different memory management/owning. Present a popover does not retain the memory, so you can't transfer the ownership of your popviewcontroller to the presenting object.

To avoid memory leak, you have to adopt the UIPopoverControllerDelegate and implement the DidDismissPopOver method as follow:

- (void)popoverControllerDidDismissPopover:(UIPopoverController *)popoverController {
    [popoverController release];
}

This way, you can safe alloc and present a PopOver:

-(void)showSearch:(id)sender {
    SearchViewController *searchVC = [[SearchViewController alloc] init];
    UIPopoverController *popVC = [[UIPopoverController alloc] initWithContentViewController:searchVC];
    popVC.delegate = self;
    [popVC setPopoverContentSize:CGSizeMake(320, 100)];
    [popVC presentPopoverFromRect:CGRectMake(200, 200, 320, 100) inView:self.view permittedArrowDirections:0 animated:YES];
    [searchVC release];
}
Silvester answered 17/11, 2010 at 10:26 Comment(4)
Beware, searchVC is leaking if you do it this way. Add an autorelease.Ziwot
Yes, searchVC is leaked. Instead of an autorelease, a simple release will also work. Add this to the last line: [searchVC release];Dilisio
As documentation for popoverControllerDidDismissPopover: says: "The popover controller does not call this method in response to programmatic calls to the dismissPopoverAnimated: method. If you dismiss the popover programmatically, you should perform any cleanup actions immediately after calling the dismissPopoverAnimated: method.". So if you use dismissPopoverAnimated: you'll also need to call release after it, otherwise you'll get a leak.Stingaree
Accepting this answer at long last. Thanks all for the contributions. It's obnoxious that this control behaves differently from ones with nominally similar interaction patterns.Philipps
J
1

Presenting a modal view controller retains the UIViewController. This is actually not clear from the docs. However, I tested it using the following code...

NSLog(@"BEFORE %d", [self.setupViewController retainCount]);
[self.navigationController presentModalViewController:self.setupViewController animated:YES];
NSLog(@"AFTER %d", [self.setupViewController retainCount]);

The self.setupViewController is already retained locally, but presenting it output the following:

2010-05-19 10:07:36.687 LocateMe[27716:207] BEFORE 1
2010-05-19 10:07:36.762 LocateMe[27716:207] AFTER 3

So it is probably being retained in the local modalViewController property, as well as in the view hierarchy. Dismissing it will balance these.

So bottom line is, retain it if you want to control it directly, but you don't have to.

EDIT - Just to be clear, the correct pattern is to always retain an object if you set yourself as its delegate. That's because you should be setting the delegate to nil in your dealloc for safety. Practically though, a modal controller is always going to be dismissed before you dealloc, so it's not an issue. You'll notice Apple also breaks this rule in [UIView setAnimationDelegate:], which actually retains the delegate you set.

Josettejosey answered 19/5, 2010 at 17:10 Comment(7)
I would also add that much of Apple's sample code initializes a UIViewController, presents it modally, and then releases it. Check out the AddMusic example.Josettejosey
Does the same go for popovers and action sheets?Philipps
Yes, you can fire UIAlertView and then release it. Or you can retain it if you want to do something to it. Either way is fine, just make sure you balance your retain/releases.Josettejosey
This is not correct-- if you allocated an autoreleased popover and present it, you'll crash because it gets dealloc'd after being presented. This implies that you must hold onto a reference to the popover until it's dismissed unless you are OK leaking it. This seems totally lame, and inconsistent with the other stuff, but there you are.Philipps
It is correct, and the alert view does NOT leak. Go read the docs (bit.ly/b25V5U). Apple repeatedly demonstrates a pattern of alloc-present-release for both modal windows and alert views.Josettejosey
@Josettejosey - Is the alloc-present-release pattern used for the UIPopoverController as well?Dekow
@Dekow - I don't see an Apple example, but I'm sure it's the same. Since you set a delegate on it, the correct pattern should be to retain it, and then set that delegate to nil in your dealloc to be safe. Technically, that's the right way to do things, but since it automatically dies when your view controller does, it's probably not strictly necessary.Josettejosey

© 2022 - 2024 — McMap. All rights reserved.