Разрешение одного вызова метода за раз для метода категории ios (@synchronized)

У меня есть 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 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 ответа

Решение

Предполагая, что вы хотите запустить следующую анимацию после завершения предыдущей. Таким образом, вы можете использовать некоторые общие 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();
    }
}

Если речь идет только об анимации, вы можете проверить if ([someView.layer animationForKey:@"sameKeyAsOnCreation"] == nil), Чем вы только добавите анимацию, если она в данный момент не запущена.

Вы также можете использовать связанные объекты для хранения состояния самостоятельно (анимация запущена / не запущена).

Попробуйте использовать это. И использовал self в @synchronized директивы.

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

Примечание: @synchronized() Директива принимает в качестве единственного аргумента любой объект Objective-C, включая self. Этот объект известен как семафор взаимного исключения или мьютекс. Это позволяет потоку заблокировать часть кода, чтобы предотвратить его использование другими потоками.

Другие вопросы по тегам