Как я могу программно приостановить NSTimer?

Я использую NSTimer для создания рендеринга в iPhone на базе OpenGL. У меня есть модальное диалоговое окно, которое появляется и запрашивает ввод пользователя. Пока пользователь предоставляет ввод, я хотел бы «приостановить», например, что-то вроде этого:

[myNSTimer pause]; 

Я использую этот синтаксис, потому что я делаю такие вещи, как:

 [myNSTimer invalidate]; 

когда я хочу, чтобы он остановился.

Как я могу программно приостановить NSTimer?

Отсюда:

http://discussions.apple.com/thread.jspa?threadID=1811475&tstart=75

«Вы можете сохранить время, прошедшее с момента запуска таймера … Когда таймер начнет хранить дату в переменной NSDate. Затем, когда пользователь переключается … используйте метод timeIntervalSinceNow в classе NSDate, чтобы хранить сколько прошло время … обратите внимание, что это даст отрицательное значение для timeIntervalSinceNow. Когда пользователь возвращает это значение для установки соответствующего таймера.

Я не думаю, что есть способ приостановить и перезапустить таймер. Я столкнулся с подобной ситуацией. ”

Просто подумал о том, чтобы обновить небольшие исправления до ответа kapesoftware :

 NSDate *pauseStart, *previousFireDate; -(void) pauseTimer:(NSTimer *)timer { pauseStart = [[NSDate dateWithTimeIntervalSinceNow:0] retain]; previousFireDate = [[timer fireDate] retain]; [timer setFireDate:[NSDate distantFuture]]; } -(void) resumeTimer:(NSTimer *)timer { float pauseTime = -1*[pauseStart timeIntervalSinceNow]; [timer setFireDate:[previousFireDate initWithTimeInterval:pauseTime sinceDate:previousFireDate]]; [pauseStart release]; [previousFireDate release]; } 

То, как я это сделал, – это сохранить дату запуска NSTimer в переменной, а затем установить дату выхода в INFINITY.

Когда я делаю паузу:

 pauseStart = [[NSDate dateWithTimeIntervalSinceNow:0] retain]; previousFiringDate = [timer firingDate]; [timer setFiringDate:INFINITY] 

Когда я приостанавливаю, я добавляю количество времени, в течение которого таймер был приостановлен до предыдущей даты увольнения:

 float pauseTime = -1*[pauseStart timeIntervalSinceNow]; [timer setFireDate:[previousFireDate initWithTimeInterval:pauseTime sinceDate:previousFireDate]]; 

Это сделало его намного легче, чем беспокоиться о недействительности и повторной инициализации таймера. У меня было много таймеров, поэтому я просто поместил их в массив и сделал это со всеми из них. Я подclassифицировал NSTimer, чтобы сохранить предыдущийFiringDate, связанный с этим таймером.

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

В моем случае у меня была переменная «секунды», а другая «timerIsEnabled». Когда я хотел приостановить таймер, просто сделал timerIsEnabled ложным. Поскольку переменная секунд была только увеличена, если timerIsEnabled был истинным, я исправил свою проблему. Надеюсь это поможет.

Самый простой способ, которым я это сделал, состоял в следующем:

 -(void) timerToggle{ if (theTimer == nil) { float theInterval = 1.0/30.0; theTimer = [NSTimer scheduledTimerWithTimeInterval:theInterval target:self selector:@selector(animateBall:) userInfo:nil repeats:YES]; } else { [theTimer invalidate]; theTimer = nil; } } 

Вот категория на NSTimer которая позволяет использовать функции паузы и возобновления.

Заголовок:

 #import  @interface NSTimer (CVPausable) - (void)pauseOrResume; - (BOOL)isPaused; @end 

Реализация:

 #import "NSTimer+CVPausable.h" #import  @interface NSTimer (CVPausablePrivate) @property (nonatomic) NSNumber *timeDeltaNumber; @end @implementation NSTimer (CVPausablePrivate) static void *AssociationKey; - (NSNumber *)timeDeltaNumber { return objc_getAssociatedObject(self, AssociationKey); } - (void)setTimeDeltaNumber:(NSNumber *)timeDeltaNumber { objc_setAssociatedObject(self, AssociationKey, timeDeltaNumber, OBJC_ASSOCIATION_RETAIN); } @end @implementation NSTimer (CVPausable) - (void)pauseOrResume { if ([self isPaused]) { self.fireDate = [[NSDate date] dateByAddingTimeInterval:[self.timeDeltaNumber doubleValue]]; self.timeDeltaNumber = nil; } else { NSTimeInterval interval = [[self fireDate] timeIntervalSinceNow]; self.timeDeltaNumber = @(interval); self.fireDate = [NSDate distantFuture]; } } - (BOOL)isPaused { return (self.timeDeltaNumber != nil); } @end 

Старый вопрос, но я просто написал легкий class полезности, чтобы выполнить именно то, что ищет OP.

https://github.com/codeslaw/CSPausibleTimer

Поддерживает повторяющиеся таймеры. Надеюсь, это пригодится!

Основываясь на ответах @Thiru и @ kapesoftware, я создал категорию Objective-C на NSTimer, используя Associated Objects для приостановки и возобновления таймера.

 #import  @interface NSTimer (PausableTimer) @property (nonatomic, retain) NSDate *pausedDate; @property (nonatomic, retain) NSDate *nextFireDate; -(void)pause; -(void)resume; @end 

 @implementation NSTimer (PausableTimer) static char * kPausedDate = "pausedDate"; static char * kNextFireDate = "nextFireDate"; @dynamic pausedDate; @dynamic nextFireDate; -(void)pause { self.pausedDate = [NSDate date]; self.nextFireDate = [self fireDate]; [self setFireDate:[NSDate distantFuture]]; } -(void)resume { float pauseTime = -1*[self.pausedDate timeIntervalSinceNow]; [self setFireDate:[self.nextFireDate initWithTimeInterval:pauseTime sinceDate:self.nextFireDate]]; } - (void)setPausedDate:(NSDate *)pausedDate { objc_setAssociatedObject(self, kPausedDate, pausedDate, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (NSDate *)pausedDate { return objc_getAssociatedObject(self, kPausedDate); } - (void)setNextFireDate:(NSDate *)nextFireDate { objc_setAssociatedObject(self, kNextFireDate, nextFireDate, OBJC_ASSOCIATION_RETAIN_NONATOMIC); } - (NSDate *)nextFireDate { return objc_getAssociatedObject(self, kNextFireDate); } 

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

Не стесняйтесь повторно использовать мою категорию в NSTimer :

https://github.com/keeshux/ios-components/tree/master/Components/Categories/NSTimer%2BPause

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

При создании таймера инициализируйте начальное время, например:

 self.startDate=[NSDate date]; self.timeElapsedInterval=[[NSDate date] timeIntervalSinceDate:self.startDate];//This ``will be 0 //second at the start of the timer.`` myTimer= [NSTimer scheduledTimerWithTimeInterval:1.0 target:self `selector:@selector(updateTimer) userInfo:nil repeats:YES]; 

`Теперь в методе таймера обновления:

  NSTimeInterval unitTime=1; -(void) updateTimer { if(self.timerPaused) { //Do nothing as timer is paused } else{ self.timerElapsedInterval=timerElapsedInterval+unitInterval; //Then do your thing update the visual timer texfield or something. } } 

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

Следующий код работает с ответом на нажатие кнопки паузы.

 -(IBAction)Pause:(id)sender { static BOOL *PauseToggle; if(!PauseToggle) { [timer invalidate]; timer = nil; PauseToggle = (BOOL *) YES; } else { timer = [NSTimer scheduledTimerWithTimeInterval:0.04 target:self selector:@selector(HeliMove) userInfo:nil repeats:YES]; PauseToggle = (BOOL *) NO; } } 

Код, приведенный ниже, предназначен для использования с scrollview, который регулярно выводит контент, и завершает цикл назад, но та же логика может использоваться для любой кнопки паузы / перезапуска.

Таймер запускается при загрузке (initiateFeatureTimer) и приостанавливает взаимодействие с пользователем (начнет метод перетаскивания), позволяя пользователю просматривать контент до тех пор, пока ей нравится. Когда пользователь поднимает свой палец (закончится drag and drop), функция Boolean сбрасывается, но также вы можете добавить немного больше задержки.

Таким образом, скроллер не перемещается сразу на подъеме пальцев, он более реактивен для пользователя.

 //set vars, fire first method on load. featureDelay = 8; //int featureInt = featureDelay-1; //int featurePaused = false; //boolean -(void)initiateFeatureTimer { featureTimer = [NSTimer scheduledTimerWithTimeInterval:1.0f target:self selector:@selector(moveFeatureScroller) userInfo:nil repeats:true]; [featureTimer fire]; } -(void)moveFeatureScroller { if (!featurePaused){ //check boolean featureInt++; if (featureInt == featureDelay){ featureInt = 0; //reset the feature int /*//scroll logic int nextPage = (featurePage + 1) * w; if (featurePage == features.count-1){ nextPage = 0; } [featureScroller setContentOffset:CGPointMake(nextPage, 0)]; */ } } } -(void)scrollViewWillBeginDragging:(UIScrollView *)scrollView { featurePaused = true; //pause the timer } -(void)scrollViewWillEndDragging:(UIScrollView *)scrollView withVelocity:(CGPoint)velocity targetContentOffset:(inout CGPoint *)targetContentOffset { featurePaused = false; //restart the timer featureInt = -3; //if you want to add an additional delay } 

Вот простой быстрый таймер паузы / воспроизведения.

https://github.com/AnthonyUccello/Swift-Pausable-Timer/blob/master/Timer.swift

Если ваш временной интервал огня является толерантным, вы можете использовать CADisplayLink вместо NSTimer . Потому CADisplayLink поддержка -pause .

 displayLink = [[CADisplayLink displayLinkWithTarget:self selector:@selector(fireMethod:)]; displayLink.frameInterval = approximateVaue;//CADisplayLink's frame rate is 60 fps. [displayLink addToRunLoop:[NSRunLoop currentRunLoop] forMode:NSDefaultRunLoopMode]; //pause [displayLink pause]; 

Я также нуждался в pausable NSTimer. После прочтения этой темы и ваших ответов и осознания того, что мне нужно только то, чтобы установить firedate таймера в отдаленное будущее, а затем вернуться к Теперь я сделал категорию для NSTimer с помощью методов Pause и Resume. Поэтому я могу просто приостановить таймер, вызвав [myTimer pause]; и возобновить, вызвав [myTimer resume]; методы. Вот оно, надеюсь, что это поможет кому-то.

Интерфейс:

 #import  @interface NSTimer (Pausable) -(void)pause; -(void)resume; @end 

Реализация:

 #import "NSTimer+Pausable.h" @implementation NSTimer (Pausable) -(void)pause { [self setFireDate:[NSDate dateWithTimeIntervalSinceNow:[NSDate distantFuture]]]; //set fireDate to far future } -(void)resume { [self setFireDate:[NSDate date]]; } @end 
  • Одновременные распознаватели жестов в Iphone SDK
  • UITextView линейчатый фон, но неправильная высота строки
  • objective-C: Как получить адрес маршрутизатора?
  • Как правильно представить popover из UITableViewCell с помощью UIPopoverArrowDirectionRight или UIPopoverArrowDirectionLeft
  • Замена на устаревший размерWithFont: в iOS 7?
  • Как я могу программно проверить, присутствует ли клавиатура в приложении iOS?
  • Ширина пикселя текста в UILabel
  • Возможно открытие всплывающих ссылок в UIWebView?
  • Сколько стоит разработка приложения для iPhone?
  • установить фоновое изображение для всего приложения iPhone / iPad
  • Синглтон в iOS 5?
  • Давайте будем гением компьютера.