Как я могу программно приостановить NSTimer? - PullRequest
42 голосов
/ 07 декабря 2008

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

[myNSTimer pause];

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

[myNSTimer invalidate];

когда я хочу, чтобы это прекратилось.

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

Ответы [ 15 ]

35 голосов
/ 20 июля 2011

Только что подумал об обновлении мелких исправлений до 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];
}
22 голосов
/ 07 декабря 2008

Отсюда:

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

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

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

12 голосов
/ 23 сентября 2010

Я достиг этого, сохранив дату запуска 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]];

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

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

8 голосов
/ 16 мая 2011

Самый простой способ, которым мне удалось это сделать, был такой:

-(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;
    }
}
8 голосов
/ 10 марта 2009

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

5 голосов
/ 13 августа 2013

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

Заголовок:

#import <Foundation/Foundation.h>

@interface NSTimer (CVPausable)

- (void)pauseOrResume;
- (BOOL)isPaused;

@end

Реализация:

#import "NSTimer+CVPausable.h"
#import <objc/runtime.h>

@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
2 голосов
/ 03 января 2015

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

#import <objc/runtime.h>

@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);
}

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

2 голосов
/ 28 марта 2013

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

https://github.com/codeslaw/CSPausibleTimer

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

1 голос
/ 06 августа 2014

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

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

0 голосов
/ 11 апреля 2017

Если ваш интервал времени пожара терпимый, вы можете использовать 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];
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...