Retain/release pattern for UIPopoverController, UI

2020-02-02 12: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?

回答1:

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];
}


回答2:

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.