NSTimer не запускается при возникновении события uiscrollview

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

Но, всякий раз, когда происходит 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"];
}

Ответы

Ответ 1

Приложения 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 Внизу вы увидите определения режимов, которые вы можете выбрать. Кроме того, у легенды есть это, вы можете писать свои собственные режимы, но мало кто когда-либо жил, чтобы рассказать рассказ, который испугался.

Ответ 2

Еще одна вещь (с)

  1. используйте метод timerWithTimeInterval, чтобы избежать добавления таймера к циклу выполнения в DefaultMode
  2. использовать mainRunLoop

Так:

self.myTimer = [NSTimer timerWithTimeInterval: 280 target: self selector: @selector (doStuff) userInfo: nil повторяется: НЕТ]; [[NSRunLoop mainRunLoop] addTimer: self.myTimer forMode: NSRunLoopCommonModes];