Skip to content

Instantly share code, notes, and snippets.

@BigZaphod
Created July 23, 2011 20:44
Show Gist options
  • Star 3 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save BigZaphod/1101862 to your computer and use it in GitHub Desktop.
Save BigZaphod/1101862 to your computer and use it in GitHub Desktop.
// say that the object which is our _delegate is the only object retaining us
// and it calls this -processStuff method…
- (void)processStuff
{
// and then this happens:
[_delegate finishedSomething:self];
// now, in _delegate's -finishedSomething: it ends up releasing us like so:
// [_processorOfStuff release];
// if that delegate object was the only owner, do we get destroyed now?
// prior to ARC and assuming we're not in an autorelease pool, I think yes.
// so what happens when the -finishedSomething: method is done and we
// come back here and attempt:
[self doSomeFollowupStuff];
// do we crash and burn here? prior to ARC, the answer should be be yes
// if we're not in an autorelease pool, etc.
// so the fixes I would normally consider would be, if I could anticipate
// my delegate might trash me, I could put a [self retain]/[self autorelease]
// in our implementation of -processStuff here, or I might do a
// [_processorOfStuff autorelease] instead of release in _delegate's
// -finishedSomething: method to avoid the trouble.
// what is the best practice solution for this situation?
// it seems unreasonable to be able to perfectly anticipate what's going
// to happen to us while calling out to a delegate we might not control
// so guarding such calls with a [self retain]/[self autorelease] seemed
// okay but ARC bans the use of retain/release/autorelease, so does ARC
// solve this for us somehow (maybe by ensuring we don't die while executing
// a method) or is there something I'm missing?
}
@DouweM
Copy link

DouweM commented Jul 23, 2011

I take it is impossible in your specific situation to just call the delegate method after doSomeFollowupStuff?
(I am still interested in how ARC would handle the situation you describe, but if the above works as well, why not circumvent the entire situation?)

@joshaber
Copy link

I don't think ARC magically fixes this unless when you pass self to finishedSomething: it actually does a retain/autorelease (which it might do, but that also might be subject to the autorelease squashing that ARC does).

You could work around this by creating a reference to self at the beginning:

- (void)processStuff
{
    id strongSelf = self;

    ...

    [_delegate finishedSomething:self];

    ...

    [self doSomeFollowupStuff];

    // ARC will release strongSelf down here somewhere
}

@lorenbrichter
Copy link

That'd be sweet if it worked, are there any guarantees that the optimizer won't kill that?

@joshaber
Copy link

Yeah, you should probably actually use strongSelf later on:

- (void)processStuff
{
    id strongSelf = self;

    ...

    [_delegate finishedSomething:self];

    ...

    [strongSelf doSomeFollowupStuff];

    // ARC will release strongSelf down here somewhere
}

@joshaber
Copy link

(This is all untested, but it's essentially the same as the example in the WWDC ARC presentation of keeping a reference to self alive through the entirety of a block.)

@lorenbrichter
Copy link

Ah, sweet. (I need to go back and re-watch that presentation).

Did they mention how to force a delayed release? I find this useful on occasion:
[[self retain] autorelease];

@jallum
Copy link

jallum commented Jul 25, 2011

They mentioned in the video that an optimizer pass will attempt to pull out "extra" retain/releases inserted by ARC -- it seems that ARC is going to be inserting the retain/release calls before the optimizer runs. So, strongSelf should maintain a +1 until some point between it's last use and the end of it's scope. This would make the first suggestion sorta iffy, since it'd be dependent upon exactly where the compiler decides to put the release. The pattern in the second suggestion should be perfectly valid, though.

@sjmadsen
Copy link

I ran into this exact problem where I want to keep a reference to self alive for a bit longer than ARC thinks it needs to. I didn't try putting a local variable into the function because my pattern is that a UIAlertView is shown and I need to delay the release until the user taps one of the buttons.

Adding a new instance variable to the class and assigning self to it, then nil'ing it out later is sufficient to outsmart ARC.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment