我怎样才能以编程方式暂停NSTimer?
我正在使用NSTimer在基于OpenGL的iPhone应用程序中进行一些渲染。 我有一个模式对话框popup并要求用户input。 当用户提供input时,我想暂停一下,比如:
[myNSTimer pause];
我正在使用这个语法,因为我一直在做这样的事情:
[myNSTimer invalidate];
当我想要停止。
我怎样才能以编程方式暂停NSTimer?
从这里:
http://discussions.apple.com/thread.jspa?threadID=1811475&tstart=75
“你可以存储自定时器启动以来已经过去的时间量…当计时器开始将date存储在一个NSDatevariables中,然后当用户切换时…使用NSDate类中的timeIntervalSinceNow方法来存储多less时间已过…请注意,这将给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的开火date存储在一个variables中,然后将开火date设置为INFINITY。
当我暂停时:
pauseStart = [[NSDate dateWithTimeIntervalSinceNow:0] retain]; previousFiringDate = [timer firingDate]; [timer setFiringDate:INFINITY]
当我取消暂停时,我将计时器暂停的时间加到上一个开始date:
float pauseTime = -1*[pauseStart timeIntervalSinceNow]; [timer setFireDate:[previousFireDate initWithTimeInterval:pauseTime sinceDate:previousFireDate]];
这使得它比担心无效和重新初始化计时器容易得多。 我有很多定时器,所以我把它们全部放在一个数组中,并且对所有的定时器都做了这个。 为了保持与该定时器相关的previousFiringDate,我将子类NSTimer分类。
这比使用一个布尔是否被暂停要好,所以如果BOOL被设置,动作就不会发生。 这是因为如果在暂停之前即将发生什么事情,那么在您暂停之后就不会发生,因为它会被跳过。
在我的情况下,我有一个variables“秒”,另一个“timerIsEnabled”。 当我想暂停计时器时,只是将timerIsEnabled设置为false。 由于秒variables只增加,如果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
一个类别,允许暂停和恢复function。
标题:
#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
基于@Thiru和@ kapesoftware的回答,我使用关联对象在NSTimer上做了一个Objective-C类别来暂停和恢复定时器。
#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); }
它使事物保持整洁,意味着您不必创build实例variables或属性来暂停和恢复定时器。
随意在NSTimer
上重用我的类别:
https://github.com/keeshux/ios-components/tree/master/Components/Categories/NSTimer%2BPause
你不能像上面提到的那样暂停NSTimer。 所以被捕获的时间不应该依赖于计时器被解雇,我build议。 这是我最简单的解决scheme:
创build计时器时,初始化单位时间如下:
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. } }
那么,我觉得这是实现暂停计时器的最好方法。 使用一个静态variables来切换暂停和恢复。 在暂停时,使计时器无效并将其设置为零,并在恢复部分使用启动的原始代码重置计时器。
以下代码适用于单击暂停button的响应。
-(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; } }
下面的代码是用于滚动视图的,这个滚动视图会定期的带来内容,并在完成时回到前面,但是同样的逻辑可以用于任何暂停/重启button。
定时器触发加载(initiateFeatureTimer),并暂停用户交互(将开始拖动方法),允许用户看内容,只要她喜欢。 当用户抬起她的手指(将结束拖动)featurePaused布尔值被重置,而且,你可以select添加多一点的延迟。
这样,手指抬起时,滚轮不会立即移开,这对用户来说更具react native。
//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 }
如果您的火灾时间间隔是宽容的,您可以使用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];
我也需要可以抵御的NSTimer。 读完这个线程和你的答案,并意识到我唯一需要的是将计时器的fireDate设置为遥远的未来,然后返回到现在,我使用Pause和Resume方法对NSTimer进行了分类。 所以我可以通过调用[myTimer pause]来暂停计时器。 并通过调用[myTimer resume]继续; 方法。 在这里,希望它能帮助别人。
接口:
#import <Foundation/Foundation.h> @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