17

I was told by a fellow StackOverflow user that I should not use the getter method when releasing a property:

@property(nonatmic, retain) Type* variable;
@synthesize variable;

// wrong
[self.variable release]; 

// right
[variable release]; 

He did not explain in detail why. They appear the same to me. My iOS book said the getter on a property will look like this:

- (id)variable {
    return variable;
}

So doesn't this mean [self variable], self.variable, and variable are all the same?

Community
  • 1
  • 1
JoJo
  • 19,587
  • 34
  • 106
  • 162
  • That is a very dangerous recommendation; the getter will not always look like that. In fact, if that were an `atomic` property it'd -retain/-autorelease. – bbum Aug 31 '11 at 19:59

4 Answers4

13

For a retained property with no custom accessor, you can release the object by:

self.variable = nil;

This has the effect of setting the ivar (which may not be called 'variable' if you have only declared properties) to nil and releasing the previous value.

As others have pointed out, either directly releasing the ivar (if available) or using the method above is OK - what you must not do is call release on the variable returned from a getter.

jrturton
  • 118,105
  • 32
  • 252
  • 268
  • I knew I forgot something important in my answer... upvoted yours because its an important thing to understand! – MechEthan Aug 31 '11 at 19:32
  • I read in [multiple places](http://stackoverflow.com/questions/5737312/set-to-nil-in-viewdidunload-but-release-in-dealloc/5737438#5737438) that properties should be released in `dealloc` and set to nil in `viewDidUnload`. – JoJo Sep 02 '11 at 06:10
  • 1
    If you also have an ivar, you can directly release this. The point is that you can't release what is returned from the getter as this is not guaranteed to be the real underlying variable. Directly releasing the ivar does prevent any custom logic in the setter being executed, if you don't have any, it makes little to no difference. – jrturton Sep 02 '11 at 06:47
  • Are there any real world use cases for writing an accessor that doesn't return an ivar? People have listed examples on this page, but none are linked to real world use cases. – JoJo Sep 02 '11 at 18:52
  • The atomic accessors returning an autoreleased instance is a pretty good one. In my very limited experience I've not used anything else. This has been a great thread with a lot of good discussion. I think the lesson we have drawn is that using the getter is more operations, more typing, and, well, more wrong! – jrturton Sep 03 '11 at 06:03
9

You can optionally write custom getter behavior, which may result in completely different behavior. So, you cannot always assume that [variable release] has the same results as [self.variable release].

As well, you can write custom properties without an exclusive ivar backing them... it can get messy fast if you start releasing objects from references returned by getters!

There may be additional reasons that I'm unaware of...

MechEthan
  • 5,703
  • 1
  • 35
  • 30
  • This is true, but I can't image what kind of getter would alter property in a way user would not be able to release it .) – Eimantas Aug 31 '11 at 19:30
  • 1
    @Eimantas: I can't either, however, say you're releasing objects via getters in your dealloc... Code written in the custom getter may attempt to access other ivars that have already been released, resulting in a crash. Or other odd cases like that! – MechEthan Aug 31 '11 at 19:39
  • 3
    Maybe the getter could return an autoreleased copy? It would be a terrible idea, but it would still be valid. Then, in that case, releasing the value returned by the getter would crash your program by over-releasing an object. – Adam Rosenfield Aug 31 '11 at 19:39
  • 2
    There are reasons for returning autoreleased objects. You could have a property fullName implemented like `return [[[NSString alloc] initWithFormat:@"%s %s", self.firstName, self.lastName] autorelease];`. It's possible you could create a hard-to-find error if you had previously had an ivar for last name and had left around `[self.lastName release]`. If you removed the ivar `[lastName release]` would generate a compiler error reminding you. – morningstar Aug 31 '11 at 19:57
  • Atomic properties release autoreleased objects on @synthesize, IIRC. – bbum Aug 31 '11 at 20:00
4

A typical getter will look more like this:

- (id)variable {
   return [[variable retain] autorelease];
}

So if you use [self.variable release] you have an additional retain and autorelease that you don't really need when you just want to release the object and that cause the object to be released later than necessary (when the autorelease pool is drained).

Typically, you would either use self.variable = nil which has the benefit that it also sets the variable to nil (avoiding crashes due to dangling pointers), or [variable release] which is the fastest and may be more appropriate in a dealloc method if your setter has custom logic.

omz
  • 53,243
  • 5
  • 129
  • 141
4

not all getters take this form:

- (id)variable { return variable; }

...that is merely the most primitive form. properties alone should suggest more combinations, which alter the implementation. the primitive accessor above does not account for idioms used in conjunction with memory management, atomicity, or copy semantics. the implementation is also fragile in subclass overrides.

some really brief examples follow; things obviously become more complex in real programs where implementations become considerably more complex.

1) the getter may not return the instance variable. one of several possibilities:

- (NSObject *)a { return [[a copy] autorelease]; }

2) the setter may not retain the instance variable. one of several possibilities:

- (void)setA:(NSObject *)arg
{
  ...
  a = [arg copy];
  ...
}

3) you end up with memory management implementation throughout your program, which makes it difficult to maintain. the semantics of the class (and how it handles instance variables' ref counting) should be kept to the class, and follow conventions for expected results:

- (void)stuff:(NSString *)arg
{
    const bool TheRightWay = false;
    if (TheRightWay) {
        NSMutableString * string = [arg mutableCopy];
        [string appendString:@"2"];
        self.a = string;
        [string release];
        // - or -
        NSMutableString * string = [[arg mutableCopy] autorelase];
        [string appendString:@"2"];
        self.a = string;
    }
    else {
        NSMutableString * string = [arg mutableCopy];
        [string appendString:@"2"];
        self.a = string;
        [self.a release];
    }
}

failing to follow these simple rules makes your code hard to maintain and debug and painful to extend.

so the short of it is that you want to make your program easy to maintain. calling release directly on a property requires you to know a lot of context of the inner workings of the class; that's obviously bad and misses strong ideals of good OOD.

it also expects the authors/subclassers/clients to know exactly how the class deviates from convention, which is silly and time consuming when issues arise and you have to relearn all the inner details when issues arise (they will at some point).

those are some trivial examples of how calling release on the result of a property introduces problems. many real world problems are much subtler and difficult to locate.

justin
  • 104,054
  • 14
  • 179
  • 226