views:

76

answers:

6

I have the following in the header:

@property (nonatomic, retain) UIView *overlay;

And in the implementation:

@synthesize overlay;

Then:

UIView *tempOverlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)];
self.overlay = tempOverlay;
[tempOverlay release];

Isn't the tempOverlay variable above unnecessary? Can't I just do:

self.overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)];
+2  A: 

Using the retain attribute specifies that retain should be invoked on the new object, and the previous value is sent a release.

So in your second code block, the retain count of the object would become 2, since you no longer release it, and the setter is retaining it. This is unlikely to be what you want.

invariant
A: 

Yes, you can directly assign the newly created object to overlay object. If you wish, you can prove it to yourself by printing out the retain count of the object

NSLog(@"count: %d", [overlay retainCount]);
davidstites
-1 You miss the point. The object was created with alloc. You therefore own it and must release it when you are done with it which you are straight away in this case.
JeremyP
I don't think so. See the answer I gave.
MattDiPasquale
A: 

If you assign the object directly to the property, you still must release it:

self.overlay = [[[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)] autorelease];
Leg10n
This must be incorrect. See the answer I gave.
MattDiPasquale
Sorry, I didn't scroll to the right to see the `autorelease`. This is a correct solution, but I wanted to explicitly release the temp value after setting `overlay`.
MattDiPasquale
A: 

As your property is defined with (retain) any instance you set using the synthesized setter (via the self.overlay syntax) will automatically be sent a retain message:

// You're alloc'ing and init'ing an object instance, which returns an 
// instance with a retainCount of 1.
UIView *tempOverlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)];

// The overlay property is defined with (retain), so when you assign the new 
// instance to this property, it'll automatically invoke the synthesized setter, 
// which will send it a retain message. Your instance now has a retain count of 2.
self.overlay = tempOverlay;

// Send a release message, dropping the retain count to 1.
[tempOverlay release];

If you were to do:

self.overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)];

Your overlay would have a retain count of two, which will likely lead to a leak at some point in your application.

dannywartnaby
+1  A: 

A synthesized retained setter looks like :

- (void)setValue: (id)newValue
{
    if (value != newValue)
    {
        [value release];
        value = newValue;
        [value retain];
    }
}

In your case, you have two valid methods :

1) Create a temp var, alloc/init (= retained), set to property, release.

IView *tempOverlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)];
self.overlay = tempOverlay;
[tempOverlay release];

2) No temp var, set directly to ivar.

overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)];

UPDATE: If you use method 2), you have to explicitly handle the rest of memory management (not only retaining), by releasing any previous value it might have before if needed. If done only once in viewDidLoad (for instance), you can just put a [overlay release]; in dealloc.

jv42
If a synthesized retained setter looks like you have it, then what happens the first time the value is set? If you try to release the old value first, won't it crash with BAD ACCESS? Or, are all properties automatically given an initial retain count of 1?
MattDiPasquale
Should method 2) ever be used, perhaps the first time it is set? But, if you are setting it after it's already been set, then the old value is not getting released (unless done explicitly). So, that would cause a memory leak, correct?
MattDiPasquale
Initially, value is nil, and sending any message to nil (including retain/release) is a no op returning nil.
jv42
For method 2, yes, you'd need to release your ivar somewhere obviously.
jv42
A: 

Thank you for all the answers. I got some conflicting claims so I tested the following in a UITableViewController:

- (id)initWithStyle:(UITableViewStyle)style {
    if ((self = [super initWithStyle:style])) {
        NSLog(@"count: %d", [overlay retainCount]);
        self.overlay = [[UIView alloc] initWithFrame:CGRectMake(160.0f, 70.0f, 150.0f, 310.0f)];
        NSLog(@"count: %d", [overlay retainCount]);
        [overlay release]; NSLog(@"released once");
        NSLog(@"count: %d", [overlay retainCount]);     
        [overlay release]; NSLog(@"released twice");
        NSLog(@"count: %d", [overlay retainCount]);
    }
    return self;
}

I got the following console output:

  • Sometimes it ran fine:

    count: 0
    count: 2
    released once
    count: 1
    released twice
    count: 1
    
  • Other times it crashed:

    count: 0
    count: 2
    released once
    count: 1
    released twice
    Program received signal:  “EXC_BAD_ACCESS”.
    

I know the method using tempOverlay is correct. It just seems so cumbersome, but I prefer it to autorelease because I don't understand how autorelease works or when it's called. One thing is for sure. The code above is wrong because I don't want overlay to have a retain count of 2.

The weird thing is that I can't release it twice. Even when it doesn't crash, the retain count is not decremented.

Anyway, guess I'll stick with using the tempOverlay for now.

MattDiPasquale