views:

322

answers:

2

Apple is doing this in a setter method for an instance variable mainSprocket:

– (void)setMainSprocket:(Sprocket *)newSprocket {
    [mainSprocket autorelease];
    mainSprocket = [newSprocket retain];
    return;
}

Why do they send -autorelease and not -release? Would a -release have a bad effect here? Actually it should not (for my understanding), because the -release just says that the current object held by the instance variable mainSprocket is no longer used by that instance variable. For the case that anyone else is still interested in exactly that object, that method could retain it, right? So -release should be fine, I think?

+3  A: 

They're doing autorelease here in case newSprocket and mainSprocket happen to be the same object. A call to release might inadvertently deallocate the object before it can be retained on the next line, whereas the autorelease won't be processed until the autorelease pool is drained at the end of the event loop.

Consider this scenario:

Sprocket *mySprocket = [Sprocket spacelySprocket];
[sprocketManager setMainSprocket:mySprocket];

Sprocket *anotherPointerToMySprocket = mySprocket;
[sprocketManager setMainSprocket:anotherPointerToMySprocket];

The last line would cause an issue if mainSprocket wasn't autoreleased. Another convention you might sometimes see for setter code that does the same thing is:

– (void)setMainSprocket:(Sprocket *)newSprocket {
    if (newSprocket != mainSprocket) {
        [mainSprocket release];
        mainSprocket = [newSprocket retain];
    }
}

I'll leave it up to others to comment on which is more appropriate or aesthetically pleasing :-)

Jarret Hardie
Thanks. But if it is not the same object, and I call that method many times, wouldn't I run into problems with the autorelease pool? Because the pool may be drained only in the main function of the application?
Thanks
You can drain the autorelease pool yourself if you are in a function where lots of objects are created.
Georg
If the program flow you're building calls the function many times, then you may wish to employ one of Apple's other strategies for setters, rather than verbatim from their simple example that you're quoting. Either set up a special autorelease pool and drain it yourself (or drain the main autorelease pool manually, as gs suggests), or don't use autorelease... use either the identity checking if statement or the safety retain suggested by gs. The approach you take depends entirely on your needs.
Jarret Hardie
Thanks for the example. I like the last approach better, since I think that this one causes less memory problems. I think that it's always good to prefer manually releasing rather than relying on autorelease pools... but i might be wrong with that (still learning).
Thanks
If you do elect to drain the autorelease pool, you'll probably want to set up your own (which Apple calls a local autorelease pool). Draining the main one is a bit risky since other functions called before your setter are not expecting anything in the autorelease pool to be deallocated in the middle of the event loop, so there may be code that uses objects which were autoreleased in the main pool after your setter is called.
Jarret Hardie
Swanzus... sounds like you've got the basics down pat. In fact, Apple itself recommends explicit releasing if you can. Obviously, autorelease is very important (some functions just wouldn't work at all without it), and so-called "normal usage" certainly isn't going to have impact on the average application's performance or memory footprint. But yet, if you can safely do a retain/release, may as well do that :-)
Jarret Hardie
Thanks Jarret. I think I'll catch up with autorelease pools next...that's a topic I didn't dive in deeply until now.
Thanks
+4  A: 

If mainSprocket and newSprocket were the same object, it could get released if you use a simple release.

If you don't want to use autorelease, use this:

– (void)setMainSprocket:(Sprocket *)newSprocket {
    // if newSprocket and mainSprocket were the same object, 
    // it would first be retained and then released
    // and therefore not deleted.
    [newSprocket retain];
    [mainSprocket release];
    mainSprocket = newSprocket;
    // you don't need return in a void-method
    // return;
}


Why aren't you using properties? They are the Objective-C 2.0 way of doing it.

SomeObject.h

@interface SomeObject : NSObject {
    Sprocket *mainSprocket;
}

@property(retain) Sprocket *mainSprocket;

@end

SomeObject.m

@implementation SomeObject

@synthesize mainSprocket;

@end
Georg
Thanks. I do use properties, but I want to get behind the scene what's happening :)
Thanks