views:

282

answers:

2

I've been trying out some of the view code from Erica Sadun's book "The iPhone Developer's Cookbook" and found some code I don't understand. Here's the code for a loadView method:

- (void)loadView
{
 // Create the main view
 UIView *contentView = [[UIView alloc] initWithFrame: 
  [[UIScreen mainScreen] applicationFrame]];
 contentView.backgroundColor = [UIColor whiteColor];
 self.view = contentView;
   [contentView release];

 // Get the view bounds as our starting point
 CGRect apprect = [contentView bounds];

 // Add each inset subview
 UIView *subview = [[UIView alloc] 
  initWithFrame:CGRectInset(apprect, 32.0f, 32.0f)];
 subview.backgroundColor = [UIColor lightGrayColor];
 [contentView addSubview:subview];
 [subview release];
}

My question is why does she release contentView, but then use it again in [contentView addSubview:subview]? Has self.view = contentView retained contentView?

A: 

If u declare ur property like so @property(nonatomic,retain) ... TheN yes the property is retained when assigned. that is probably what's going on

Daniel
Formulating a gramatically correct answer and avoiding IM-style abbreviations will probably help avoid downvotes in the future. (I didn't downvote, I'm just saying...)
Quinn Taylor
I know , but it's hard when typing responses from the iPhone lol, when I do I write the bare minimum and can't really formulatecode well, but I think this answer would helpthe Asker anyway so I posted it
Daniel
+5  A: 

If you look in the documentation for UIViewController, you'll see that the view property is declared as:

@property(nonatomic, retain) UIView *view;

This means that when you use the setView: method (or use .view on the left hand side of the =), then whatever value you pass in will be retained. So, if you go through the code and look at retain counts, you'll get this:

- (void)loadView {
    // Create the main view
    UIView *contentView = [[UIView alloc] initWithFrame: 
            [[UIScreen mainScreen] applicationFrame]];  //retain count +1
    contentView.backgroundColor = [UIColor whiteColor];  //retain count +1
    self.view = contentView;  //retain count +2
    [contentView release];  //retain count +1

    // Get the view bounds as our starting point
    CGRect apprect = [contentView bounds];

    // Add each inset subview
    UIView *subview = [[UIView alloc] 
            initWithFrame:CGRectInset(apprect, 32.0f, 32.0f)];
    subview.backgroundColor = [UIColor lightGrayColor];
    [contentView addSubview:subview];
    [subview release];

}

I'd say that the really interesting thing is that after releasing contentView, we can still send messages to it, because the object living at the end of contentView's pointer still exists (since it was retained by calling setView:).

Dave DeLong
This is correct, but I personally avoid this style/pattern -- if at some point you decide to change that property from `retain` to `assign`, then this code will spontaneously begin crashing. Of course, this isn't an issue with the UIViewController.view property, but for your own properties it's asking for trouble down the road.
Daniel Dickison
Yes, this is exactly why it works, and it is horrible form. Once you release a particular reference you should not use it again, it is error prone. The release should either be moved too the end, or all appearances of contentView beyond the release should be changed to self.view.
Louis Gerbarg
It doesn't really qualify as a style, unless "<x> considered harmful" is a style.
Amagrammer
I disagree with a blanket generalization of it being horrible form. UIViewController is a public API, and the property attributes cannot change without breaking dependent code. This idiom is not necessarily appropriate for all situations, but it's perfect for coupling a view controller with the view it controls. Further, releasing directly after the assignment is about the closest you can get to the object creation. In fact, if there weren't an assignment to set the background color, I would probably wrap an autorelease around the object creation and assign it directly to the property.
Quinn Taylor
If it was autoreleased it would be fine, the thing that is bad form is accessing an variable through an lval after that lval has been released before it has been reassigned. In this case release and autorelease art totally different beasts, because autorelease has no chance of invalidating the data pointed to until after the pool is drained.
Louis Gerbarg
Releasing an object does not set the pointer to nil. Keep in mind that pointers effectively are integers who's value is a memory address. This in a way gives you two variables, the one on the stack which stores the memory address, and the one which is on the heap (the actual object instance). When you release an object you free the one on the heap, but nothing changes on the variable on the stack. This is why most of the time when you see a release, you also see a line setting the value to nil as well.
Lounges