I have two UIButton
, the first button will trigger the CustomeView's - beginAnimation
and the other one will trigger the - endAnimation
. when I rapidly press these two button in turn, like begin -> end -> begin -> end -> begin -> end
, I found that the CADisplayLink
can't stop. What's more, the - rotate
's fire rate is more than 60fps, became 60 -> 120 -> 180
, just like there are more than one CADisplaylink
in my main RunLoop, so is there anyway to fix it? And I need to keep the CADisplaylink
running before the view's alpha come to zero, so I put the [self.displayLink invalidate];
in the completion block, maybe this will cause this problem?
@interface CustomeView : UIView
@end
@implementation CustomeView
- (void)beginAnimation // triggered by a UIButton
{
[UIView animateWithDuration:0.5 animations:^{ self.alpha = 1.0; }];
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(rotate)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
- (void)endAnimation // triggered by another UIButton
{
[UIView animateWithDuration:0.5 animations:^{ self.alpha = 0.0; } completion:^(BOOL finished) {
[self.displayLink invalidate];
}];
}
- (void)rotate
{
// ....
}
If you call -beginAnimation
before the completion block in -endAnimation
has run -- that is, before the 0.5 second animation has finished -- you will overwrite the old self.displayLink
with the new one. Afterwards, when the completion block runs, you will invalidate the new display link, not the old one.
Use an intermediate variable to capture the value of self.displayLink
that holds the display link that you want to invalidate. Also, for good measure, set self.displayLink
to nil when you are done with it.
- (void)beginAnimation // triggered by a UIButton
{
[UIView animateWithDuration:0.5 animations:^{ self.alpha = 1.0; }];
if (self.displayLink != nil) {
// You called -beginAnimation before you called -endAnimation.
// I'm not sure if your code is doing this or not, but if it does,
// you need to decide how to handle it.
} else {
// Make a new display link.
self.displayLink = [CADisplayLink displayLinkWithTarget:self selector:@selector(rotate)];
[self.displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode];
}
}
- (void)endAnimation // triggered by another UIButton
{
if (self.displayLink == nil) {
// You called -endAnimation before -beginAnimation.
// Again, you need to determine what, if anything,
// to do in this case.
} else {
CADisplayLink oldDisplayLink = self.displayLink;
self.displayLink = nil;
[UIView animateWithDuration:0.5 animations:^{ self.alpha = 0.0; } completion:^(BOOL finished) {
[oldDisplayLink invalidate];
}];
}
}