Recursive method containing UIAnimation block, how to properly release
I did a small "loader" that I can stick on the UI when I need it. Much like the UISpinnerView.
It has some logic (I simplified the code in the block for this post) that require it to be recursively called. I do it like this:
- (void) blink {
tic开发者_开发百科k++;
if (tick > kNumberOfLights)
tick = 0;
UIView *lightOne = [self viewWithTag:kLightStartIndex];
UIView *lightTwo = [self viewWithTag:kLightStartIndex+1];
[UIView animateWithDuration:0.5
delay: 0.0
options: UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveEaseOut
animations:^{
if (tick == 0) {
[lightOne setAlpha:kLightOn];
[lightTwo setAlpha:kLightOff];
} else if (tick == 1) {
[lightOne setAlpha:kLightOff];
[lightTwo setAlpha:kLightOn];
}
}
completion:^(BOOL finished){
[self blink];
}];
}
The method [self blink]
is called when the view is added to a super view.
There are no objects retained in the Loader class, so when I remove it in the super view it is released. The problem is that if the animation block is running when I release the view, the completion block will call a deallocated object and cause the error:
(20380,0xa0a29540) malloc: * mmap(size=2097152) failed (error code=12) * error: can't allocate region
In the console and the error:
__[LoaderClass blink]_block_invoke_2
in the Debug Navigator.
How do I make sure to correctly tear down the view when it is removed from the super view?
Overriding release is usually a bad idea, but this case might be an exception to the rule.
Instance variables:
BOOL isBlinking;
BOOL releaseWhenDoneAnimating;
Initialize isBlinking = NO and releaseWhenDoneAnimating = NO.
- (void)release
{
if(!isBlinking) {
[super release];
return;
}
releaseWhenDoneAnimating = YES;
}
- (void) blink {
isBlinking = YES;
if(releaseWhenDoneAnimating) {
[super release];
return;
}
tick++;
if (tick > kNumberOfLights)
tick = 0;
UIView *lightOne = [self viewWithTag:kLightStartIndex];
UIView *lightTwo = [self viewWithTag:kLightStartIndex+1];
[UIView animateWithDuration:0.5
delay: 0.0
options: UIViewAnimationOptionAllowUserInteraction | UIViewAnimationOptionCurveEaseOut
animations:^{
if (tick == 0) {
[lightOne setAlpha:kLightOn];
[lightTwo setAlpha:kLightOff];
} else if (tick == 1) {
[lightOne setAlpha:kLightOff];
[lightTwo setAlpha:kLightOn];
}
}
completion:^(BOOL finished){
[self blink];
}];
}
精彩评论