2010-10-28 138 views
4

我在iOS上为我的动画使用块基API。当其他动画开始时,UIView动画完成块触发

一个动画有一个完成块,该动画结束时调用该块,很好。

但是,该动画可以在用户滚动时触发多次(动画位于UITableViewCell)。当发生这种情况时,完成块被多次调用。块的finished参数始终为YES

由于动画并未真正完成(发生其他动画),我认为参数finished是NO,但事实并非如此。

我错过了什么吗?我怎样才能避免完成块被多次调用?

+0

你现在是在模拟器中执行此操作还是试图在实际设备上运行此操作?在滚动时在UITableViewCells上运行动画似乎不是合适的事情。滚动时你的帧速率是多少? – runmad 2010-11-03 03:38:32

+0

我也有类似的问题。 – karim 2010-11-08 13:51:05

回答

0

我已经解决了这个问题,看看完成块是否与该块的开始相关。

finished参数现在不相关。我已经与Apple沟通过,他们告诉我它已经在iOS 4.2中修复了。

+0

我正在使用ios5,看来问题仍然没有解决。当你说,“我通过查看完成区块是否与该区块的开始相关时解决了这个问题”,你能解释一下你的意思吗? – 2012-05-25 05:43:09

+0

我同意它看起来不像'finished'参数工作正常。我通过添加一个“animationCount”ivar来获得所需的行为,当动画开始并完成时,我会增加/减少动画。如果它是'0',我只运行我的完成块代码。 – zekel 2013-02-04 15:36:25

5

完成块被多次调用,因为在您的情况下,您的动画会被多次触发。现在发生的事情是iOS每次调用动画块时都会调用它,可能是在单独的线程中。然后,为每个动画追踪其完成,并在完成后调用相关的完成块。所以基本上,你会看到你的完成块触发多次,每次调用你的动画。请注意,与完成块关联的布尔值特定于该完成块,它不会以任何方式引用不同的动画。

回顾一下,您遇到的仅仅是并发的影响。如果这不是你想要的行为,那么你需要相应地修改你的代码。如果您希望动画一次触发一个动画,则可以使用NSLock(NSConditionLock用于使用关联条件变量进行高级控制),或者如果您愿意,可以直接使用互斥锁和Posix pthreads库来创建要执行的关键部分以互相排斥的方式。

+0

如果没有必要,我宁愿不使用NSLock。但如果这是唯一的解决方案,我会做。但是有一件事情没有得到,布尔值什么时候会是NO?因为与此完成块关联的动画实际上未完成。 – gcamp 2010-11-02 14:43:11

+0

我知道NSLock会伤害性能,但是我没有看到任何其他解决方案来序列化并发调用。与动画块的完成处理程序关联的布尔值不应该为NO,否则,我不会将其称为“完成”块。无论如何,即使iOS在关联动画实际终止之前调用完成块,您也可以简单地检查块中的布尔值,并仅在其为YES时才作出反应。 – 2010-11-02 19:04:46

2

不确定何时启动动画以及它们是否循环(如UIActivityView微调器或其他东西) - 听起来像是表视图滚动的每一个像素?

在任何情况下,也许你可以使用UIScrollView的委托方法,并告诉每一个小区来scrollViewWillBeginDragging:启动动画,告诉每个单元停在scrollViewDidEndDragging:

您可以为您的UITableViewCell一个布尔isAnimating,如果动画目前正在进行中,什么都不做。或者坚持你现在拥有的任何东西,并使用一个布尔静止,但只有在动画没有动画时才会触发动画。然后在您的finished参数中设置isAnimatingNO

if (isAnimating) { 
     // ... do nothing 
    } else { 
     [UIView animateWithDuration:0.3f 
          animations:^{ 
            // animations... 
            isAnimating = YES; 
            } 
          completion:^{ 
            isAnimating = NO; 
            } 
      ];  
} 
+0

我的帧速率可以(约45-50 fps)。但是你的解决方案将不起作用,因为当“真实”动画仍在进行时调用“错误”完成块。 – gcamp 2010-11-08 18:43:41