Timers 通常是跟NSRunLoop一起使用。但是他们的精确度是有限的,如果你只是想在将来的某个时间点执行某个操作的话,完全可以不用timer而做到这些。
如果你只是想在将来的某个时刻执行某些操作,可以使用下面的方法:
performSelector: withObject:afterDelay:
performSelectorOnMainThread:withObject:waitUntilDone:
上面的这个方法可以达到在某个线程执行操作的目的,通过
cancelPreviousPerformRequestsWithTarget:
方法可以取消或者延迟一个消息以及相关方法的执行。
Timer的使用
当你创建一个timer类实例的时候,必须要配置timer的一些方面,比如当timer实例对象开始工作或者激活的时候应该向哪个对象发送哪个消息。并且需要对timer绑定一个run loop来启动timer,有些创建方法会自动做这些操作,最后如果不想使用的时候需要停止timer。
timer对象的创建
大体来说有三种方法来创建一个timer对象:
1、在当前run loop 中 Scheduling一个timer
2、先创建一个timer然后在在一个run loop 中注册
3、初始化一个在某个确定的时刻激活的timer
在所有的方法中,timer对象都需要明确在timer激活的情况下,需要向什么对象发送什么消息,以及它能否重复。在一些方法中,你还可以设置 user info字典。你可以将你认为在timer对象激活情况下有用的代码添加到这个字典当中。
因为有run loop维持着timer,从对象的生命周期的角度来说,当scheduled(安排)一个timer对象之后并没有必要对其进行引用操作。但是在大多数情况下,你有可能需要在你认为恰当的时候停掉timer的运行,甚至是在timer开始之前,在这种情况下,就需要对timer对象保持引用。这样就可以在任何恰当的时候停掉timer。如果你创建了一个没有进入安排的timer对象的话,应该对对象保持一种强引用,以防止这个timer对象在你再次使用的时候已经被销毁。
timer对象强引用着它的任务,也就是说只要timer对象没有被停掉,它的任务就不会被销毁。
也就是说在任务的dealloc方法中停掉timer并不会起任何作用。
@interface TimerController : NSObject // The repeating timer is a weak property. @property (weak) NSTimer *repeatingTimer; @property (strong) NSTimer *unregisteredTimer; @property NSUInteger timerCount; - (IBAction)startOneOffTimer:sender; - (IBAction)startRepeatingTimer:sender; - (IBAction)stopRepeatingTimer:sender; - (IBAction)createUnregisteredTimer:sender; - (IBAction)startUnregisteredTimer:sender; - (IBAction)stopUnregisteredTimer:sender; - (IBAction)startFireDateTimer:sender; - (void)targetMethod:(NSTimer*)theTimer; - (void)invocationMethod:(NSDate *)date; - (void)countedTimerFireMethod:(NSTimer*)theTimer; - (NSDictionary *)userInfo; @end
1 - (NSDictionary *)userInfo { 2 return @{ @"StartDate" : [NSDate date] }; 3 } 4 5 - (void)targetMethod:(NSTimer*)theTimer { 6 NSDate *startDate = [[theTimer userInfo] objectForKey:@"StartDate"]; 7 NSLog(@"Timer started on %@", startDate); 8 } 9 10 - (void)invocationMethod:(NSDate *)date { 11 NSLog(@"Invocation for timer started on %@", date); 12 }
Scheduled Timers
下面的这两个类方法将会自动的将timer对象注册到当前的NSRunLoop对象的默认模认式(NSDefaultRunLoopMode)当中当中:
1 scheduledTimerWithTimeInterval:invocation:repeats: 2 scheduledTimerWithTimeInterval:target:selector:userInfo:repeats:
1 - (IBAction)startOneOffTimer:sender { 2 3 [NSTimer scheduledTimerWithTimeInterval:2.0 4 target:self 5 selector:@selector(targetMethod:) 6 userInfo:[self userInfo] 7 repeats:NO]; 8 }
两秒钟之后,timer对象被激活,然后就会被移除。
下面的这个方法是创建一个重复执行的timer对象的方法:
1 - (IBAction)startRepeatingTimer:sender { 2 3 // Cancel a preexisting timer. 4 [self.repeatingTimer invalidate]; 5 6 NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:0.5 7 target:self selector:@selector(targetMethod:) 8 userInfo:[self userInfo] repeats:YES]; 9 self.repeatingTimer = timer; 10 }
用一个特定的激活时间来初始化一个timer对象:
可以创建一个timer对象,并且给他一个
initWithFireDate:interval:target:selector:userInfo:repeats:
方法。一旦创建,唯一可以修改的是它的开始时间(使用:setFireDate:)。其他的属性在创建之后就是不可变的了。如果要启用这个timer对象,必须将其添加到一个run loop中去。
下面的这个方法可以展示如何根据一个给定的启用时间来创建一个timer对象,并且通过将其添加到一个run loop中来启用这个timer对象:
1 - (IBAction)startFireDateTimer:sender { 2 3 NSDate *fireDate = [NSDate dateWithTimeIntervalSinceNow:1.0]; 4 NSTimer *timer = [[NSTimer alloc] initWithFireDate:fireDate 5 interval:0.5 6 target:self 7 selector:@selector(countedTimerFireMethod:) 8 userInfo:[self userInfo] 9 repeats:YES]; 10 11 self.timerCount = 1; 12 NSRunLoop *runLoop = [NSRunLoop currentRunLoop]; 13 [runLoop addTimer:timer forMode:NSDefaultRunLoopMode]; 14 }
停止一个timer 对象:
可以通过给timer对象发送一个invalidate消息来停止timer对象。也可以给一个不重复的timer对象发送一个invalidate方法在启用之前停掉timer对象。
1 - (IBAction)stopRepeatingTimer:sender { 2 [self.repeatingTimer invalidate]; 3 self.repeatingTimer = nil; 4 } 5 6 - (IBAction)stopUnregisteredTimer:sender { 7 [self.unregisteredTimer invalidate]; 8 self.unregisteredTimer = nil; 9 }
1 - (void)countedTimerFireMethod:(NSTimer*)theTimer { 2 3 NSDate *startDate = [[theTimer userInfo] objectForKey:@"StartDate"]; 4 NSLog(@"Timer started on %@; fire count %d", startDate, self.timerCount); 5 6 self.timerCount++; 7 if (self.timerCount > 3) { 8 [theTimer invalidate]; 9 } 10 }
这个方法可以在timer对象启用三次之后停用。因为这个timer是作为一个方法的参数在传递的,三次之后就没有必要将timer对象再作为一个参数了。如果你想更早的停掉timer对象,就需要对timer对象进行引用。