Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

does alloc init'ing a property twice result in a memory leak in ARC Objective C?

I have a piece of code which is functionally equivalent to:

self.myProperty = [[MyClass alloc] initWithBla:bla blur:blur];
self.myProperty = [[MyClass alloc] initWithBla:bla blur:blur];

I'm not actually doing this twice in a row as illustrated above, but it's effectively what's happening. My question is, does this cause any memory leaks under ARC Objective C? Is the memory allocated for self.myProperty in the first invocation reclaimed before self.myProperty is reassigned to point at a newly allocated instance of MyClass?

like image 447
Bryce Thomas Avatar asked Dec 12 '22 02:12

Bryce Thomas


1 Answers

There's no leak in the property implementation, and as long as you're using ARC, no leak where you're assigning to the property either.

Calling:

self.myProperty = something

invokes a generated accessor that goes something like this (assuming _myProperty is the backing ivar for your property):

- (void)setMyProperty:(MyClass *)anInstance
{
    if (_myProperty == anInstance)
        return;
    [_myProperty release];
    _myProperty = [anInstance retain];
}

The object formerly held by the property is released, so it doesn't leak here. And if you're using ARC, the code generated by the compiler works the same way.

You're correct in noting the potential for a leak, though not (as far as I can tell) where you suspect.

self.myProperty = [[MyClass alloc] initWithBla:bla blur:blur];

This creates a new object with a retain count of +1 and assigns it to the property (which then retains it again: +2). So, your code here still has an ownership reference to that object. When you repeat that line, you've orphaned the first reference, which you still own -- if you're using ARC, you're fine: it makes sure that object gets released. If not, that orphaned object is still retained: you do indeed have a leak. The appropriate non-ARC thing to do would be:

self.myProperty = [[[MyClass alloc] initWithBla:bla blur:blur] autorelease];

But, again, using ARC you're just fine.


To address a related question from comments: this is still okay -- but only under ARC -- if you're assigning to a local variable instead of to self.myProperty. When you write:

id myLocalVar;
myLocalVar = [[MyClass alloc] initWithBla:bla blur:blur];
myLocalVar = [[MyClass alloc] initWithBla:bla blur:blur];

the compiler turns it into:

__strong id myLocalVar; // variables are strong by default
myLocalVar = [[MyClass alloc] initWithBla:bla blur:blur];
[myLocalVar release]; // ARC inserts release before myLocalVar is reassigned to another object
myLocalVar = [[MyClass alloc] initWithBla:bla blur:blur];
// ... sometime later ...
[myLocalVar release]; // ARC inserts another release when myLocalVar goes out of scope
like image 80
rickster Avatar answered May 20 '23 10:05

rickster