Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Does UIViewController's presentModalViewController:animated: retain the modal controller?

This has implications on the way I interact with my modal controllers. When I first started out in iOS development, I assumed that UIViewController did not retain the modally presented view. Well, really it was more like I had no reason to assume it did retain them. This left me with fairly awkward attempts at releasing them when I knew they would have finished their dismissal animations:

_myViewController = [[UIViewController alloc] init];
[self. present modalViewController:_myViewController animated:YES];
/* 
Some stuff, then in a different method all together,
probably as the result of a delegate callback or something...
*/
[self dismissModalViewControllerAnimiated:YES];
[_myViewController performSelector:@selector(release) withObject:nil afterDelay:0.5f];

Then, I saw the modalViewController property of UIViewController and thought, "Man, I hope it retains that property when a modal view controller is presented." Sure enough, I logged the retain count on several of these attempts and noticed a general increase immediate after the call to presentModalViewController:animated: (I know, retain counts are not a perfect metric). So, somewhere along the line, I have started using a much nicer pattern where I assume that any controller object I present modally is retained by the presenting controller. This lets me write the standard present code:

UIViewController* myViewController = [[UIViewController alloc] init];
[self presentModalViewController:myViewController animated:YES];
[myViewController release]; // <- Fire and forget!

Now, of course, there is no awkwardness: no need to wait for an animation to finish, or even keep a reference to the presented controller if I don't need it. I can blindly dismiss it later and not worry about leaking. I like it.

I have logged many a dealloc in my modally presented controllers and they are always called precisely when I want, which leads me to feel confident in my approach: UIViewController's presentModalViewController:animated: retains the presented controller as the modalViewController property.

But, and this is the meat of this question, I realized that I can't confirm this as documented behavior. And if it's not documented, I should not feel nearly as safe as I do, because Apple makes no promises about the longevity of undocumented behavior. The modalViewController property is publicly readonly, so I can only assume a retain behind the scenes, and the documentation on presentModalViewController:animated: says only:

Sets the modalViewController property to the specified view controller.

"Sets" could be assign or retain. Nothing I read blatantly confirms or denies my position. Since this is an assumption I make often, I would really love it if someone could point out a fact that I have missed somewhere in the bowels of documentation to put my mind at ease about the legitimacy of this practice.

EDIT: In the ebb and flow of day-to-day life in the iOS SDK, I found myself in the header for UIViewController and started reading some of it. I gleaned some useful info that reminded me of this question and I decided to post it, in the event some future user stumbles upon this question and wants as much info as possible to satisfy their paranoia of a very standard practice. The little morsel is simply this, from the @interface ivar block in UIViewController.h:

UIViewController *_childModalViewController;

As opposed to these other declarations:

UIViewController *_parentViewController; // Nonretained
NSHashTable      *_childViewControllers; // Nonretained

The comments seem to explicitly state what is not retained. By virtue of a lack of comment on the modal view controller ivar declaration, it would seem it is retained.

like image 497
Matt Wilding Avatar asked Dec 18 '10 08:12

Matt Wilding


People also ask

What is a UIViewController?

The UIViewController class defines the shared behavior that's common to all view controllers. You rarely create instances of the UIViewController class directly. Instead, you subclass UIViewController and add the methods and properties needed to manage the view controller's view hierarchy.


2 Answers

The memory management rules of Objective-C define the behaviour, so it doesn't need to expressly document that it retains the modal view controller. If an object needs to keep a passed object around after the method has finished executing, it will retain the object unless otherwise specified.

So in this case, you should just pass the view controller to presentModalViewController:animated: and then release it (or use autorelease).

This applies everywhere in Objective-C. If an object takes another object as method input, you never have to retain that object on its behalf.

As requested in the comments, if you read Apple's documentation on memory management, then you'll find the section on Weak References, which states:

Important: In Cocoa, references to table data sources, outline view items, notification observers, and delegates are all considered weak (for example, an NSTableView object does not retain its data source and the NSApplication object does not retain its delegate). The documentation only describes exceptions to this convention.

This actually states that this is a convention in itself and that exceptions will be stated in the documentation, however, going to the documentation for NSTableView and looking at the setDataSource: method, we see:

Discussion In a managed memory environment, the receiver maintains a weak reference to the data source (that is, it does not retain the data source, see Communicating With Objects). After setting the data source, this method invokes tile.

This method raises an NSInternalInconsistencyException if anObject doesn’t respond to either numberOfRowsInTableView: or tableView:objectValueForTableColumn:row:.

like image 63
d11wtq Avatar answered Sep 21 '22 06:09

d11wtq


Hmm good question! I'm not totally sure about your assumptions. The property in question is defined in the docs as:

@property(nonatomic, readonly) UIViewController *modalViewController

As you point out, it doesn't specify how it is stored.

This document: http://developer.apple.com/library/mac/#documentation/Cocoa/Conceptual/ObjectiveC/Articles/ocProperties.html

in fact, states that if retain/assign/copy is not specified, that assign is the default behavior.


I've also read d11wtq's reply, but am not sure I totally agree. I agree about the conventions about obj-c memory management, but there are many cases where framework methods don't retain properties (think weak references, delegates, etc). I hope somebody can confirm your assumptions.

like image 23
D.C. Avatar answered Sep 23 '22 06:09

D.C.