UIView beginAnimations в одном экземпляре класса запускает beginAnimations в другом экземпляре того же класса

Надеюсь, что вы можете помочь или объяснить, что здесь происходит, так как я не очень хорошо UIGraphics контексты.

Я определил класс, который автоматически прокручивает метку назад и вперед в своем фрейме, когда текст метки слишком длинный для данного пространства в основном представлении контроллеров представления.

Он состоит из прокрутки, которая соответствует выделенному пространству в родительском представлении, и содержит UILabel (в подклассе), размер которого соответствует размеру текста. (UILabel - это подпредставление в родительском представлении прокрутки).

Scrollview фиксирует анимацию, которая прокручивает UILabel влево -> вправо, затем, когда анимация заканчивается, я запускаю делегата.

(void)animationDidStop:animationID(NSString*)finished:(NSNumber *)finished context:(void *)context' 

который сбрасывает некоторые числа и перезапускает анимацию, прокручивая ее в обратном направлении вправо -> влево

Это работает очень хорошо.

Однако, если я добавлю еще один экземпляр этой "метки прокрутки" где-нибудь еще в главном представлении контроллеров представления, то одна из анимаций остановится, и AnimationDidStop Делегат уволен, он заново запускает анимацию для другого объекта метки "прокрутка".

Я попробовал следующее, чтобы изолировать запуск анимации без каких-либо положительных результатов. Передача контекста представлений и идентификатора beginAnimations, а затем их захват в (void)animationDidStop метод... не имеет никакого значения. Это заставляет меня думать, что метод, кажется, не принимает

Ниже приведен код, который выполняет анимацию, и код, который перезапускает его в другом направлении.

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

Надеюсь, вы можете объяснить, почему. Благодарю.

- (void)beginAnimationWithOrgigin:(CGPoint)origin Terminus:(CGPoint)terminus {


NSLog (@"Message %@ in context %@",((UILabel*)_textLabel).text,_ctx);

CGFloat text_width = ((UILabel*)_textLabel).frame.size.width;
CGFloat display_width = self.frame.size.width;

if ( text_width > display_width ) {
    float duration = (text_width - display_width)/40;
    [self setContentOffset:origin];

    [UIView beginAnimations:((UILabel*)_textLabel).text context:_ctx];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
    [UIView setAnimationDelay:1.0];
    [UIView setAnimationDuration:duration];
    [UIView setAnimationRepeatCount:1];
    [self setContentOffset:terminus];

    [UIView commitAnimations];

}
}


- (void)animationDidStop:(NSString *)animationID
            finished:(NSNumber *)finished
             context:(void *)context
{

NSLog(@"Animation Did stop context = %@",context);

if ([animationID isEqualToString:((UILabel*)_textLabel).text]){

    static BOOL forward = NO;
    if ([finished boolValue]) {

        CGPoint origin;
        CGPoint terminal_origin;

        if (forward){
            origin = CGPointMake(0, 0);
            terminal_origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
        }else{

            terminal_origin = CGPointMake(0, 0);
            origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
        }

        forward = !forward;
        [self beginAnimationWithOrgigin:origin Terminus:terminal_origin];
    }
}
}

РЕДАКТИРОВАТЬ: Добавлено 28/5/14 @ 13:14 После того, как A-Lives посоветовал насчет использования статики... изменил код, чтобы использовать его метку в качестве флага, чтобы подсказать изменение направления при прокрутке. ЭТО ИСПРАВИЛО ПРОБЛЕМУ

- (void)beginAnimationWithOrgigin:(CGPoint)origin Terminus:(CGPoint)terminus Direction:(NSString*)direction{

if (!direction)direction = @"FORWARD";

NSLog (@"Message %@ in context %@",((UILabel*)_textLabel).text,_ctx);

CGFloat text_width = ((UILabel*)_textLabel).frame.size.width;
CGFloat display_width = self.frame.size.width;

if ( text_width > display_width ) {
    float duration = (text_width - display_width)/40;
    [self setContentOffset:origin];

    [UIView beginAnimations:direction context:_ctx];
    [UIView setAnimationDelegate:self];
    [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
    [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
    [UIView setAnimationDelay:1.0];
    [UIView setAnimationDuration:duration];
    [UIView setAnimationRepeatCount:1];
    [self setContentOffset:terminus];

    [UIView commitAnimations];

}
}



- (void)animationDidStop:(NSString *)animationID
            finished:(NSNumber *)finished
             context:(void *)context
{

NSLog(@"Animation Did stop context = %@",context);
NSString *direction;
CGPoint origin;
CGPoint terminal_origin;

    if (![animationID isEqualToString:@"FORWARD"]){
        origin = CGPointMake(0, 0);
        terminal_origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
        direction = @"FORWARD";
    }else{

        terminal_origin = CGPointMake(0, 0);
        origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
        direction = @"BACKWARD";
        }

[self beginAnimationWithOrgigin:origin Terminus:terminal_origin Direction:direction];
}

1 ответ

Решение

Проблема заключалась в том, что мы забыли, что статика - это обычные статические переменные C, которые доступны по всему приложению. (то есть, не инкапсулированные в области, которая их определяла.)

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

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

Модифицированный рабочий код:

- (void)beginAnimationWithOrgigin:(CGPoint)origin Terminus:(CGPoint)terminus Direction:(NSString*)direction{

    if (!direction)direction = @"FORWARD";

    NSLog (@"Message %@ in context %@",((UILabel*)_textLabel).text,_ctx);

    CGFloat text_width = ((UILabel*)_textLabel).frame.size.width;
    CGFloat display_width = self.frame.size.width;

    if ( text_width > display_width ) {
        float duration = (text_width - display_width)/40;
        [self setContentOffset:origin];

        [UIView beginAnimations:direction context:_ctx];
        [UIView setAnimationDelegate:self];
        [UIView setAnimationDidStopSelector:@selector(animationDidStop:finished:context:)];
        [UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
        [UIView setAnimationDelay:1.0];
        [UIView setAnimationDuration:duration];
        [UIView setAnimationRepeatCount:1];
        [self setContentOffset:terminus];

        [UIView commitAnimations];

    }
}



- (void)animationDidStop:(NSString *)animationID
        finished:(NSNumber *)finished
         context:(void *)context
{

    NSLog(@"Animation Did stop context = %@",context);
    NSString *direction;
    CGPoint origin;
    CGPoint terminal_origin;

    if (![animationID isEqualToString:@"FORWARD"]){
        origin = CGPointMake(0, 0);
        terminal_origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
        direction = @"FORWARD";
    }else{

        terminal_origin = CGPointMake(0, 0);
        origin = CGPointMake(((UILabel*)_textLabel).frame.size.width - self.frame.size.width, ((UILabel*)_textLabel).frame.origin.y);
        direction = @"BACKWARD";
        }

    [self beginAnimationWithOrgigin:origin Terminus:terminal_origin Direction:direction];
}
Другие вопросы по тегам