Friday, April 29, 2011

Is this an objective-c memory leak?

I know that if you do the following you most certainly have a memory leak:

id foo = [[NSObject alloc] init];
foo = nil;

But, what if you're using self.foo, a property with retain? And your code instead looks like the following:

foo = [[NSObject alloc] init];
self.foo = nil;

Is that still a memory leak since the accessor releases the memory first before setting it to nil?

From stackoverflow
  • self.foo = nil would translate into

    [nil retain]
    [foo release]
    foo = nil
    

    There is no memory leak here.

  • Nope, the second example is not a memory leak. In fact, that's how I deal with retain properties in my dealloc method. It's just a lot cleaner.

    The only thing you have to be careful about is making sure not to write

    self.foo = [[NSObject alloc] init];
    

    or else you'll double-retain the object and end up with a memory leak.

    Marc Charbonneau : Keep in mind using properties in dealloc is usually discouraged in case the accessor method is changed to modify another ivar (which might have already been released). I just use release instead.
    e.James : @Alex: +1 for an excellent warning, but -1 for the suggestion to use self.foo = nil in a dealloc method!
    Jason Coco : @eJames self.foo = nil is the way Apple were recommending doing it in the dealloc method originally and is everywhere in their sample code.
    Alex : I think for run-of-the-mill @synthesize accessors, the property syntax is the way to go. It's good enough for Apple! My thinking is, why spend two lines doing what you could do in one?
    Tom Andersen : Properties in Obj-C 2 look nice, but they add complexity - especially when you can mix and match. I think they should have gone further. Maybe we will will get there in another 15 years with ObjC 3.
  • I don't think so as by doing self.foo = nil you are essentially using the setter and getting the memory management along for free.

  • Properties make it your code look like assignment, but in reality they're the same as traditional accessor methods you might have written yourself prior to Obj-C 2.0. With properties Obj-C is simply generating the accessor methods behind the scenes for you instead using the keywords you specify in the declaration (assuming you use @synthesize and don't write your own accessor methods anyway).

  • No, there is no memory leak. The code in your second example is logically equivalent to

    foo = [[NSObject alloc] init];
    [nil retain];
    [foo release];
    foo = nil;
    

    because the @synthesized setter is logicall equivalent to

    - (void)setFoo:(id)newFoo {
      [newFoo retain];
      [foo release];
      foo = newFoo;
    }
    

    It's worth noting that setting foo directly is probably not something you want to do outside of an init method. If you assign a value to foo directly, you bypass the automatic KVO notification (you would have to wrap your assignment in a willChangeValueForKey:/didChangeValueForKey: pair) and you break any subclass' behavior if it overrides the setFoo: method, expecting all modifications of foo to go through the setter.

    You assign directly to foo in an init method because the setFoo: method or a subclass' overriden setFoo: method may have side-effects or depend on the instance's fully initialized.

    Similarly, you would use [foo release] rather than self.foo = nil; in the -dealloc method for the same reasons.

  • All the answers so far assume that “foo” in the first line of the second example is the instance variable behind the foo property. This is the default behavior.

    If the foo that the first line assigns to is a local variable, then the foo property is irrelevant, and you will leak the object unless you release it later in the method.

    If foo is an instance variable, but the foo property is actually backed by a different instance variable, or no instance variable at all, then (a) you are writing hard-to-maintain code and (b) it may be a leak.

    Finally, echoing the previous answers: If foo is the instance variable backing the foo property, then this is not a leak, since the setFoo: method that you call in the second line will release the object that you put in the foo instance variable in the first line.

0 comments:

Post a Comment