Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/ios/96.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Ios 允许一次调用一个类别方法(@synchronized)_Ios_Objective C_Animation_Uiviewanimation_Synchronized - Fatal编程技术网

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

Ios 允许一次调用一个类别方法(@synchronized),ios,objective-c,animation,uiviewanimation,synchronized,Ios,Objective C,Animation,Uiviewanimation,Synchronized,我有一个UIViewController和一个用于向UIViewController添加方法的类别。该类别中有一种方法: @implementation UIViewController (AlertAnimationsAndModalViews) -(void)someAddedMethod { UIView *someView; //do some animation with the view that lasts 3 seconds //remove the vi

我有一个UIViewController和一个用于向UIViewController添加方法的类别。该类别中有一种方法:

@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动画的持续时间。。。是在一个单独的线程中运行的,鉴于我无法在类别中创建IVAR,我无法真正使用@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),然后将视图滑出屏幕并删除。由于这是一个类别,我无法添加实例变量。。
因此,我想要实现的是,如果对该方法进行了多个调用,我希望第一个调用在不等待的情况下执行,但之后的每个调用都要等待,直到前一个调用完成。

尝试使用此调用。并在@
synchronized
指令中使用了
self

- (void)criticalMethod {
    @synchronized(self) {
        // Critical code.
    }
}

注意:指令
@synchronized()
将任何Objective-C对象(包括self)作为其唯一参数。此对象称为互斥信号量或互斥信号量。它允许一个线程锁定一段代码,以防止其他线程使用它。

如果只是关于动画,您可以检查
如果([someView.layer animationForKey:@“sameKeyAsOnCreation”]==nil)
。然后,如果动画当前未运行,则仅添加动画


您还可以使用关联的对象存储自己的状态(动画正在运行/未运行)。

假设您希望在上一个动画完成后启动下一个动画。 这样,您可以使用一些共享的
NSMutableArray*\u 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();
    }
}

如果确实要等到“3秒动画”完成后再允许再次调用您的方法运行,则此操作将不起作用。是否还要等到动画完成后再运行?是的,请参阅编辑的版本。我最初使用数组实现了类似的实现。它是一个递归方法,将“方法调用”存储在数组中,在该方法结束之前,它将再次调用自身并检查是否添加了任何调用,如果是,则再次添加。但由于将其移动到一个类别中,除非传入一个共享数组,否则我无法使用这些变量,我认为这破坏了使用类别的理由。您可以使用
objc\u setassociated object
在类别中添加ivar。再看看我更新的解决方案。哇,这真有效!谢谢!只要几个问题也可以提高我的理解力如果可以的话。。。当您声明静态数组时,为什么要将其设置为nil,然后检查(!animationQueue)是否为alloc和init?如果你把它设为零,你会一直被分配并初始化它吗?动画末尾的block nextAction()的作用是什么?静态变量
animationQueue
的作用方式与全局变量相同。最初它是
nil
,每次函数调用都会检查它是否需要分配
NSMutableArray
的实例。一旦分配,
animationQueue
将变为非零。
nextAction
只是队列中缓存的
showMessageBlock
对象之一。