简体   繁体   中英

Effect of 'myObj = [[[[MyClass alloc] init] autorelease] retain];'?

I've just downloaded the Facebook iOS SDK and I noticed that in the sample code that comes with the SDK whenever it creates an instance of the Facebook class it does it like this:

_facebook = [[[[Facebook alloc] init] autorelease] retain];

where _facebook is a member variable of the calling object (ie not a local variable).

Can anyone explain exactly what's the point of autoreleasing and then retaining it?

It effectively does nothing beyond consuming some cycles and memory.

Or, more precisely, in a correctly written application, it does nothing. In an incorrectly written application, it might mask a bug by lengthening the lifespan of the _facebook object. However, it isn't a real fix.

I found a similar line of code in http://github.com/facebook/facebook-ios-sdk/blob/master/sample/DemoApp/Classes/DemoAppViewController.m If that is what you are referring to then, yes, it is nonsense.

While it's possible that the code you found was just sloppy, that pattern DOES have a meaning.

"alloc, autorelease, retain" implies that the object is referenced in two places:

  • As a return value on the call stack (autorelease style)
  • By the FB SDK itself (the 'retain')

This matters if the two references can be released independently. For example, if the SDK can release its reference BEFORE the call stack has completed and drained the autorelease pool. Ok, this is pretty nuanced; what do I mean?

Consider these cases:

A) the actual code

_facebook = [[[[Facebook alloc] init] autorelease] retain];

_facebook now has a retain count of 2, and expects 2 calls to 'release': 1 from whoever called "retain", and 1 at some point in the future when the NSAutoreleasePool drains.

B) the simple "alternative" proposed (NOT equivalent)

_facebook = [[Facebook alloc] init];

_facebook has a retain count of 1 and will be destroyed when 'release' is called (potentially a big problem if the autorelease pool hasn't drained yet and the call stack is still using the object)

Why does this matter? Imagine some code like this:

@implementation (Thinger)
+(id) make_new_thing
{
    return my_copy_of_thing = [[[[Thing alloc] init] autorelease] retain];
}
+(id) forget_about_thing
{
    if (my_copy_of_thing != nil) {
        [my_copy_of_thing release];
        my_copy_of_thing = nil;
    }
}
@end


void foo() {
    NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
    id thing = [Thinger make_new_thing];
    [Thinger forget_about_thing];
    ...
    [thing useThing]; // implementation B would break here !
    [pool drain];
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM