如何以编程方式暂停NSTimer?

MrD*_*ase 42 iphone cocoa-touch objective-c

我正在使用NSTimer在基于OpenGL的iPhone应用程序中进行渲染.我有一个模式对话框弹出并请求用户输入.当用户提供输入时,我想"暂停",例如:

[myNSTimer pause];
Run Code Online (Sandbox Code Playgroud)

我正在使用这种语法,因为我一直在做这样的事情:

[myNSTimer invalidate];
Run Code Online (Sandbox Code Playgroud)

当我希望它停止.

如何以编程方式暂停NSTimer?

Thi*_*iru 35

刚想到更新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];
}
Run Code Online (Sandbox Code Playgroud)

  • 而不是`[NSDate dateWithTimeIntervalSinceNow:0]`你可以简单地做`[NSDate date]`. (4认同)

Bob*_*toe 22

从这里:

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

"你可以存储自定时器启动以来已经过去的时间...当计时器开始将日期存储在NSDate变量中.然后当用户切换时...使用NSDate类中的方法timeIntervalSinceNow来存储多少时间已过...请注意,这将为timeIntervalSinceNow提供负值.当用户返回时使用该值来设置适当的计时器.

我认为没有办法暂停和重启计时器.我遇到了类似的情况."

  • 谢谢你的回复.也许它可以通过摆脱第一个计时器来解决...然后在用户提供输入后制作一个全新的计时器. (3认同)
  • 那不一样。如果您暂停一个计时器,则在下一个计时器事件之前还有一些时间。如果改为丢弃它并开始一个新的事件,则它始终具有事件发生之前的原始时间,这是错误的。 (2认同)

小智 12

我完成此操作的方法是将NSTimer的触发日期存储在变量中,然后将触发日期设置为INFINITY.

当我暂停时:

pauseStart = [[NSDate dateWithTimeIntervalSinceNow:0] retain];
previousFiringDate = [timer firingDate];
[timer setFiringDate:INFINITY]
Run Code Online (Sandbox Code Playgroud)

当我取消暂停时,我将计时器暂停的时间加到上一个触发日期:

float pauseTime = -1*[pauseStart timeIntervalSinceNow];
[timer setFireDate:[previousFireDate initWithTimeInterval:pauseTime sinceDate:previousFireDate]];
Run Code Online (Sandbox Code Playgroud)

这使得比担心无效和重新初始化计时器更容易.我有很多计时器,所以我把它们全部放在一个数组中,然后对所有这些计时器执行此操作.我将NSTimer子类化,以保持与该计时器关联的previousFiringDate.

这也比使用BOOL更好,无论它是否被暂停,因此如果设置了BOOL,则不会发生动作.这是因为如果在暂停之前发生了某些事情,那么在您取消暂停之后就不会发生这种情况,因为它刚刚被跳过.


小智 8

在我的情况下,我有一个变量'秒',另一个'timerIsEnabled'.当我想暂停计时器时,只是将timerIsEnabled设为false.由于只有在timerIsEnabled为true时,seconds变量才会递增,我修复了我的问题.希望这可以帮助.


小智 8

我设法做到的最简单的方法是这样的:

-(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;
    }
}
Run Code Online (Sandbox Code Playgroud)


Car*_*zey 5

这是一个NSTimer允许暂停和恢复功能的类别.

标题:

#import <Foundation/Foundation.h>

@interface NSTimer (CVPausable)

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

@end
Run Code Online (Sandbox Code Playgroud)

执行:

#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
Run Code Online (Sandbox Code Playgroud)