2012-02-01 5 views
14

У меня есть UIImageView, размещенный в UIScrollView. В основном UIImageView имеет очень большую карту и создает анимацию по предопределенному пути с направленным направлением навигации «стрелки».NSTimer не срабатывает при возникновении события uiscrollview

Но, когда происходит появление uiscrollevents, я думаю, что MainLoop зависает, а NSTimer не запускается, а анимация останавливается.

Есть ли существующее свойство, которое решает эту проблему, в UIScrollView, CAKeyFrameAnimation или NSTimer?

//viewDidLoad 
    self.myTimer = [NSTimer scheduledTimerWithTimeInterval:0.05 target:self selector:@selector(drawLines:) userInfo:nil repeats:YES]; 

- (void)drawLines:(NSTimer *)timer { 

    CALayer *arrow = [CALayer layer]; 
    arrow.bounds = CGRectMake(0, 0, 5, 5); 
    arrow.position = CGPointMake(line.x1, line.y1); 
    arrow.contents = (id)([UIImage imageNamed:@"arrow.png"].CGImage); 

    [self.contentView.layer addSublayer:arrow]; 

    CAKeyframeAnimation* animation = [CAKeyframeAnimation animation]; 
    animation.path = path; 
    animation.duration = 1.0; 
    animation.rotationMode = kCAAnimationRotateAuto; // object auto rotates to follow the path 
    animation.repeatCount = 1; 
    animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; 
    animation.fillMode = kCAFillModeForwards; 

    [arrow addAnimation:animation forKey:@"position"]; 
} 
+0

Возможный дубликат [UIScrollView приостанавливает NSTimer при прокрутке] (http://stackoverflow.com/questions/7059366/uiscrollview-pauses-nstimer-while-scrolling) –

ответ

51

Приложения iOS работают на NSRunLoop. Каждый NSRunLoop имеет разные способы выполнения для разных задач. Например, по умолчанию nstimer планируется запустить под NSDefaultRunMode на NSRunLoop. Это означает, однако, что некоторые UIEvents, скроллинг, один из них, прерывают таймер и помещают его в очередь для запуска, как только событие перестает обновляться. В вашем случае, для того, чтобы получить таймер не будет прервана, вы должны запланировать его на другой режим, а именно NSRunLoopCommonModes, например, так:

self.myTimer = [NSTimer scheduledTimerWithTimeInterval:280 
                   target:self 
                   selector:@selector(doStuff) 
                   userInfo:nil 
                   repeats:NO]; 
    [[NSRunLoop currentRunLoop] addTimer:self.myTimer forMode:NSRunLoopCommonModes]; 

Этот режим позволит таймер не будет прервана прокрутка , Вы можете найти более подробную информацию об этом здесь: https://developer.apple.com/documentation/foundation/nsrunloop Внизу вы увидите определения режимов, которые вы можете выбрать. Кроме того, легенда имеет это, вы можете писать свои собственные режимы, но мало кто когда-либо жил, чтобы рассказать сказку, испуганную.

+0

Хорошее объяснение. – Robert

+2

Эй @ GregPrice. Спасибо за объяснение, даже через 3 года после. Тем не менее, документ говорит, что 'scheduleTimerWithTimeInterval: ...' создает таймер и * планирует его в текущем цикле выполнения в режиме по умолчанию *. Итак, почему вы добавляете его дважды в RunLoop по умолчанию, а не только в режиме NSRunLoopCommonModes? – Martin

+0

'UIScrollView' запускает цикл выполнения в' UITrackingRunLoopMode', который отличается от 'NSDefaultRunLoopMode'. Недостаточно запланировать таймер для режима по умолчанию, если вы также хотите, чтобы он работал в других режимах. –