This is my pattern:
1) SpecialView creates a MessageView and holds a strong reference to it.
2) User taps a button in MessageView which causes it to fade out. MessageView then tells it's delegate, SpecialView, that it faded out completely.
3) SpecialView releases MessageView.
The problem is this:
- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context {
[self.delegate messageViewFadedOut:self]; // delegate releases us...
// self maybe got deallocated... BOOM!
// now what? method of a zombie returns? stack freaks out?
} // does it even return?
In the last line I'm calling the delegate, which in turn immediately releases MessageView. -fadedOut:finished:context: is called by a core animation didStopSelector callback.
My fear is that the MessageView instance is going to be deallocated immediately before the -fadedOut:finished:context: fully returned, causing very nasty random bugs
Once upon a time, a old veteran programmer told me: "Never cut the branch on which you're sitting on."
So in order to make sure the instance survives until this method returns, I made a retain-autorlease-dance before calling the delegate:
- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context {
//[[self retain] autorelease];
[self.delegate messageViewFadedOut:self]; // delegate releases us...
}
However, under ARC, retain-autorelease dances are not allowed anymore (the migration tool won't allow it) and there seems to be no way to force the ARC system to do something like this.
So I came up with this strategy instead:
- (void)fadedOut:(NSString*)animationID finished:(NSNumber*)finished context:(void*)context {
[self.delegate performSelector:@selector(messageViewFadedOut:) withObject:self afterDelay:0];
}
The delayed performSelector hopefully lets the method fully return. As far as I know a delay of 0 still guarantees that the selector is performed in the next run loop iteration rather than immediately.
There's a good chance this is bogus as well.
How can I correctly resolve this problem of one object asking another to destroy the last reference to it with the chance that the object get's deallocated before the method that made the call to the other object has a chance to fully return? Can there be something like a stack trace zombie?
And how must I solve something like this under ARC?