允许一次调用一个方法到类别方法ios(@synchronized)

时间:2013-05-23 08:04:26

标签: ios objective-c animation uiviewanimation synchronized

我有一个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),然后将视图滑出屏幕并移除。由于这是一个类别,我无法添加实例变量.. 所以我想要实现的是,如果对此方法进行了多次调用,我希望第一次调用无需等待即可执行,但之后每次调用都要等到上次调用完成。

3 个答案:

答案 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。此对象称为互斥信号量互斥锁。它允许线程锁定一段代码以防止其他线程使用它。

相关问题