Использовать большую центральную диспетчеризацию для вызова блока, когда установлена ​​переменная - PullRequest
1 голос
/ 14 февраля 2012

Мне нужно было вызвать метод, как только для логического значения было установлено значение NO. Boolean устанавливается в YES, когда анимация начинается и когда она заканчивается, она устанавливается в NO.

Пользователь нажимает кнопку, чтобы вызвать блок, он может нажать кнопку, когда анимация происходит или когда это не так. Но блок должен ждать, пока анимация не будет завершена.

Можно ли использовать цикл while и великую центральную диспетчеризацию для достижения этого или есть лучший способ (т. Е. Не использовать пустой цикл while или существующий ранее способ)

dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
dispatch_async(queue, ^{
    while ([self isAnimating]) {}
    dispatch_async(dispatch_get_main_queue(), ^{
        [self doSomething];
    });
});

Метод doSomething содержит вызовы методов UIKit, поэтому у меня есть вторая dispatch_async функция, которая выполняет его в главном потоке.

РЕДАКТИРОВАТЬ: забыл сказать, что первоначальная анимация не то, что у меня есть доступ (это написано Apple)

1 Ответ

4 голосов
/ 14 февраля 2012

Вы можете использовать новые UIView API-интерфейсы блочной анимации.Например:

[UIView animateWithDuration:1.0 animations:^{
    // Animation here
} completion:^(BOOL b){
    // Completion here
}];

Или, если анимация имеет неизвестную продолжительность, рассмотрите возможность использования @property для BOOL и использования наблюдения значения ключа.

Редактировать:

Я думаю, sudo rm -rf NSTimer может быть проще всего реализовать.Хотя вы можете использовать KVO, это не самый простой способ начать работу, а таймеры просты.Вот базовый пример того, как вы могли бы реализовать таймер условно в зависимости от потребности в нем.

-(void)doSomethingTimerTarget:(NSTimer *)timer{
    if ([self isAnimating]) return;
    else {
        [timer invalidate];
        [self doSomething:nil];
    }
}
-(IBAction)doSomething:(id)sender{
    if (sender && [self isAnimating]){ // if sender is nil then `doSomethingTimerTarget:` called the method no need to check again
        [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(doSomethingTimerTarget:) userInfo:nil repeats:YES];
    }
    else {
        NSLog(@"actually doing something");
        // Actually do something here
    }
}

Одна из вещей, которую вы можете сначала добавить, это отключить кнопку, когда она нажата и должнадождитесь выполнения, чтобы предотвратить множественные запросы.

Редактировать: Ответ: «KVO было бы лучше, но как я мог предотвратить его, когда пользователь не нажал кнопку, и анимациязавершите, используйте другую BOOL, например pressedButton "

Для начала, да, простой BOOL будет работать.Но помните, что вам не нужно соблюдать ключевые значения в течение полного рабочего дня.В приведенном выше примере кода таймера, где создается таймер, замените его вызовом на addObserver:.., затем при обратном вызове удалите наблюдателя.Таким образом, вы наблюдаете только тогда, когда это важно, вам не нужно поддерживать отдельный BOOL.Вот непроверенный макет:

-(void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context{
    if ([keyPath isEqualToString:/*YourKeypath*/] && ![self isAnimating]){
        [self removeObserver:self forKeyPath:/*YourKeypath*/];
        [self doSomething:nil];
    }
}
-(IBAction)doSomething:(id)sender{
    if (sender && [self isAnimating]){ // if sender is nil then the observe method called this method no need to check `isAnimating` again
        [self addObserver:self forKeyPath:/*YourKeypath*/...//etc
    }
    else {
        NSLog(@"actually doing something");
        // Actually do something here
    }
}
...