CADisplayLink失效后无法停止

CADisplayLink can't stop after invalidated

我有两个 UIButton,第一个按钮将触发 CustomeView 的 - beginAnimation,另一个将触发 - endAnimation。当我依次快速按下这两个按钮时,如begin -> end -> begin -> end -> begin -> end,我发现CADisplayLink根本停不下来。更何况- rotate的射速已经超过60fps,变成了60 -> 120 -> 180,就像我的主RunLoop里多了一个CADisplaylink一样,请问有什么方法可以解决吗?而且我需要在视图的alpha变为零之前保持CADisplaylink 运行,所以我将[self.displayLink invalidate];放在完成块中,也许这会导致这个问题?

@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
{
    // ....
}

如果您在 -endAnimation 中的完成块有 运行 之前调用 -beginAnimation -- 也就是说,在 0.5 秒动画完成之前 -- 您将覆盖旧的 self.displayLink 用新的。之后,当完成块 运行s 时,您将使新显示 link 无效,而不是旧显示。

使用中间变量捕获 self.displayLink 的值,该值保存要使显示 link 无效的值。此外,为了更好地衡量,在完成后将 self.displayLink 设置为 nil。

- (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];
        }];
    }
}