我有一个UIViewController和一个用于向UIViewController添加方法的Category。该类别中有一种方法:
@implementation UIViewController (AlertAnimationsAndModalViews)
-(void)someAddedMethod
{
UIView *someView;
//do some animation with the view that lasts 3 seconds
//remove the view and return
}
在任何视图控制器中我都可以调用此方法
[self someAddedMethod];
但是,我只想让这个方法一次运行一个。例如,如果我一个接一个地进行两次调用
[self someAddedMethod];//call1
[self someAddedMethod];//call2
我希望第二个电话等到第一个电话完成。我明白UIView animationWithduration ...是在一个单独的线程中运行,并且看到我无法在类别中创建iVars我真的不能使用@synchronized(someObject)..
有什么建议吗?
提前致谢!
方法如下:
-(void)showTopBannerWithHeight:(CGFloat)height andWidth:(CGFloat)width andMessage:(NSString *)message andDuration:(CGFloat)duration
{
UILabel *messageLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, -height, width, height)];
[self.view.superview addSubview:messageLabel];
[UIView animateWithDuration:0.5
delay:0
options: UIViewAnimationOptionBeginFromCurrentState
animations:^{
messageLabel.frame = CGRectMake(0, 0, SCREEN_WIDTH, height);
}
completion:^(BOOL finished){
[UIView animateWithDuration: 0.5
delay:duration
options: UIViewAnimationOptionBeginFromCurrentState
animations:^{
messageLabel.frame = CGRectMake(0, -height, SCREEN_WIDTH, height);
}
completion:^(BOOL finished){
[messageLabel removeFromSuperview];
}];
}];
}
所以我从屏幕顶部显示一个“横幅”,等待一段时间(CGFloat),然后将视图滑出屏幕并移除。由于这是一个类别,我无法添加实例变量.. 所以我想要实现的是,如果对此方法进行了多次调用,我希望第一次调用无需等待即可执行,但之后每次调用都要等到上次调用完成。
答案 0 :(得分:2)
如果只是关于动画,你可以检查if ([someView.layer animationForKey:@"sameKeyAsOnCreation"] == nil)
。如果它当前没有动画,那么你只会添加一个动画。
您还可以使用关联对象自行存储状态(动画正在运行/未运行)。
答案 1 :(得分:1)
假设你想在上一个动画完成之后开始下一个动画。
这样您就可以使用一些共享的NSMutableArray* _animationQueue
存储空间:
-(void)someAddedMethod
{
NSTimeInterval duration = 3.0;
void (^animationBlock)() = ^{
//do some animations here
self.view.frame = CGRectOffset(self.view.frame, 40, 0);
};
__block void (^completionBlock)(BOOL) = ^(BOOL finished){
[_animationQueue removeObjectAtIndex:0];
if([_animationQueue count]>0) {
[UIView animateWithDuration:duration animations:_animationQueue[0] completion:completionBlock];
}
};
[_animationQueue addObject:animationBlock];
if([_animationQueue count]==1) {
[UIView animateWithDuration:duration animations:animationBlock completion:completionBlock];
}
}
注意,您不需要任何@synchronized
功能,因为一切都在主线程上。
更新:以下代码完全符合您的要求:
-(void)showTopBannerWithHeight:(CGFloat)height andWidth:(CGFloat)width andMessage:(NSString *)message andDuration:(CGFloat)duration
{
static NSMutableArray* animationQueue = nil;
if(!animationQueue) {
animationQueue = [[NSMutableArray alloc] init];
}
void (^showMessageBlock)() = ^{
UILabel *messageLabel = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, width, height)];
messageLabel.text = message;
[self.view.superview addSubview:messageLabel];
[UIView animateWithDuration: 0.5
delay:duration
options:UIViewAnimationOptionBeginFromCurrentState
animations:^{
messageLabel.frame = CGRectOffset(messageLabel.frame, 0, -height);
}
completion:^(BOOL finished){
[messageLabel removeFromSuperview];
[animationQueue removeObjectAtIndex:0];
if([animationQueue count]>0) {
void (^nextAction)() = [animationQueue objectAtIndex:0];
nextAction();
}
}];
};
[animationQueue addObject:showMessageBlock];
if([animationQueue count]==1) {
showMessageBlock();
}
}
答案 2 :(得分:0)
尝试使用此功能。并在@ self
指令中使用synchronized
。
- (void)criticalMethod {
@synchronized(self) {
// Critical code.
}
}
注意: @synchronized()
指令将 Objective-C 对象作为唯一参数,包括self。此对象称为互斥信号量或互斥锁。它允许线程锁定一段代码以防止其他线程使用它。