3

用户可以通过滑动手势启动动画。我想阻止对动画的重复调用,以确保动画一旦开始,在完成之前不能再次启动——如果用户不小心多次滑动,可能会发生这种情况。

我想大多数人使用布尔标志 ( BOOL isAnimatingFlag) 以底部显示的方式实现此控制。我以前在应用程序中做过很多次这样的事情——但我从来没有 100% 确定我的标志是否保证具有我想要的值,因为动画使用块并且我不清楚我的动画完成的线程是什么块正在运行。

这种方式(阻止重复动画)对于多线程执行是否可靠?

/* 'atomic' doesn't 
* guarantee thread safety
* I've set up my flag as follows:
* Does this look correct for the intended usage?
*/
@property (assign, nonatomic) BOOL IsAnimatingFlag;

//…

@synthesize IsAnimatingFlag

//…

-(void)startTheAnimation{

// (1) return if IsAnimatingFlag is true
if(self.IsAnimatingFlag == YES)return;

/* (2) set IsAnimatingFlag to true
* my intention is to prevent duplicate animations
* which may be caused by an unwanted double-tap
*/
self.etiIsAnimating = YES;


    // (3) start a new animation
    [UIView animateWithDuration:0.75 delay:0.0 options:nil animations:^{

    // animations would happen here...

    } completion:^(BOOL finished) {

    // (4) reset the flag to enable further animations
        self.IsAnimatingFlag = NO;
    }];
}
4

3 回答 3

4

如果您不希望用户多次触发手势,请禁用手势

- (void)startTheAnimation:(id)sender
{
  [sender setEnabled:NO];

  [UIView animateWithDuration:0.75 delay:0.0 options:nil animations:^{

    // animations would happen here...

  } completion:^(BOOL finished) {
    [sender setEnabled:YES];
  }];
}

更新

手势也有一个enabled属性,因此您可以使用与按钮相同的想法并更改它的启用状态

于 2013-03-01T14:36:45.320 回答
2

动画完成块将始终在主线程上运行。

UIView Class Reference的示例中,您可以看到[view removeFromSuperview]直接从块中调用它。这意味着完成块在主线程上运行,因为它是调用 UI 相关方法的唯一线程安全。

所以如果你startTheAnimation只从主线程调用,你就很好。如果不是,则无论如何都需要在主线程上调度它,因为您在其中调用了与 UI 相关的方法。

如果您需要startTheAnimation从主线程以外的其他线程调用,您可以执行以下操作:

-(void)startTheAnimation{
    dispatch_async(dispatch_get_main_queue(), ^{
        // Your code here
    });
}

当然,从用户体验的角度来看,最好是禁用按钮或以其他方式修改 UI 以指示动画正在进行中。但是,它们都是相同的代码。无论您需要做什么,您首先需要在动画开始之前禁用它,并在动画完成后重新启用。

于 2013-03-01T14:44:18.350 回答
0

在调用此方法的地方,您可以尝试使用 dispatch_once GCD 函数:

static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
    [myThingy startTheAnimation];
});
于 2013-03-01T14:36:42.043 回答