You use the NSTimer class to create timer objects or, more simply, timers. A timer waits until a certain time interval has elapsed and then fires, sending a specified message to a target object. For example, you could create an NSTimer object that sends a message to a window, telling it to update itself after a certain time interval.
你可以使用NSTimer类创建计时器对象。等到一定的时间间隔时计时器运行,发送一个消息到指定目标对象。例如,您可以创建一个NSTimer对象发送一个消息给窗口,告诉它一定时间间隔后更新。
1. 常用定时器的创建
当定时器创建完(不用scheduled
的,添加到 runloop
中)后,该定时器将在初始化时指定的 timeInterval
秒后自动触发。如果 NSTimer
的触发时间到的时候,runloop
在阻塞状态,触发时间就会推迟到下一个 runloop
周期。
1. scheduled 方式 (可单次执行)
- 创建并启动定时器。
- 默认将定时器以 NSDefaultRunLoopMode 模式添加到运行循环。
- 发生用户交互的时候,定时器会被暂停。
/*
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti
target:(id)aTarget
selector:(SEL)aSelector
userInfo:(id)userInfo
repeats:(BOOL)yesOrNo;
参数:
TimeInterval:触发时间,单位秒
target:定时起触发对象
selector:定时器响应方法
userInfo:用户信息
repeats:是否重复执行,YES 每个指定的时间重复执行,NO 只执行一次
*/
// 创建并启动定时器
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:@selector(updateTimer:)
userInfo:nil
repeats:YES];
2. timer 方式
- 创建定时器,添加到运行循环后启动定时器。
- 将定时器以指定的模式添加到运行循环。
/*
+ (NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti
target:(id)aTarget
selector:(SEL)aSelector
userInfo:(nullable id)userInfo
repeats:(BOOL)yesOrNo;
- (void)addTimer:(NSTimer *)timer forMode:(NSString *)mode;
NSDefaultRunLoopMode:发生用户交互的时候,时钟会被暂停。时钟,网络。
NSRunLoopCommonModes:发生用户交互的时候,时钟仍然会触发,如果时钟触发方法非常耗时,
使用此方式时用户操作会造成非常严重的卡顿。用户交互,响应级别高。
*/
// 创建定时器
NSTimer *timer = [NSTimer timerWithTimeInterval:2.0
target:self
selector:@selector(updateTimer:)
userInfo:nil
repeats:YES];
// 将定时器添加到运行循环
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
2. 官方给定的5个初始化定时器方法
- +(NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
```
- (void)viewDidLoad {
[super viewDidLoad];
//初始化一个Invocation对象
NSInvocation * invo = [NSInvocation invocationWithMethodSignature:[[self class] instanceMethodSignatureForSelector:@selector(init)]];
[invo setTarget:self];
[invo setSelector:@selector(myLog)];
NSTimer * timer = [NSTimer timerWithTimeInterval:1 invocation:invo repeats:YES];
//加入主循环池中
[[NSRunLoop mainRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
//开始循环
[timer fire];
}
2. +(NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti invocation:(NSInvocation *)invocation repeats:(BOOL)yesOrNo;
```
NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:1
invocation:invo
repeats:YES];
-
+(NSTimer *)timerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;
NSTimer * timer = [NSTimer timerWithTimeInterval:1 target:self selector:@selector(myLog) userInfo:nil repeats:NO]
-
+(NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)ti target:(id)aTarget selector:(SEL)aSelector userInfo:(id)userInfo repeats:(BOOL)yesOrNo;
NSTimer * timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(myLog:) userInfo:@"123" repeats:YES]
-
-(instancetype)initWithFireDate:(NSDate *)date interval:(NSTimeInterval)ti target:(id)t selector:(SEL)s userInfo:(id)ui repeats:(BOOL)rep
NSTimer * timer = [[NSTimer alloc]initWithFireDate:[NSDate distantPast]
interval:1
target:self
selector:@selector(myLog:)
userInfo:nil
repeats:YES];
[[NSRunLoop mainRunLoop]addTimer:timer forMode:NSDefaultRunLoopMode];
```
<font style="color:brown" size='4'>注意:</font>这五种初始化方法的异同:
- 参数repeats是指定是否循环执行,YES将循环,NO将只执行一次。
- timerWithTimeInterval这两个类方法创建出来的对象如果不用 addTimer: forMode方法手动加入主循环池中,将不会循环执行。并且如果不手动调用fair,则定时器不会启动。
- scheduledTimerWithTimeInterval这两个方法不需要手动调用fair,会自动执行,并且自动加入主循环池。
- init方法需要手动加入循环池,它会在设定的启动时间启动。
3. 定时器的开启暂停关闭和属性变量
- 启动定时器
[timer setFireDate:[NSDate distantPast]];
-
暂停定时器
[timer setFireDate:[NSDate distantFuture]];
-
关闭定时器,永久关闭定时器
[timer invalidate];
-
属性变量
-
这是设置定时器的启动时间,常用来管理定时器的启动与停止
@property (copy) NSDate *fireDate; //启动定时器 timer.fireDate = [NSDate distantPast]; //停止定时器 timer.fireDate = [NSDate distantFuture];
-
这个是一个只读属性,获取定时器调用间隔时间。
@property (readonly) NSTimeInterval timeInterval;
-
这是7.0之后新增的一个属性,因为NSTimer并不完全精准,通过这个值设置误差范围
@property NSTimeInterval tolerance;
-
获取定时器是否有效
@property (readonly, getter=isValid) BOOL valid;
-
获取参数信息
@property (readonly, retain) id userInfo;
-
4. 在子线程中创建定时器
// 创建子线程
dispatch_async(dispatch_get_global_queue(0, 0), ^{
// 在子线程创建定时器
/*
scheduled 或 timer 方式创建
*/
self.timer = [NSTimer timerWithTimeInterval:1.0
target:self
selector:@selector(updateTimer:)
userInfo:nil
repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
// 启动子线程的运行循环
/*
这句代码就是一个死循环!如果不停止运行循环,不会执行添加到此句之后的 任何代码
*/
CFRunLoopRun();
// 停止子线程运行循环之前,不会执行添加到此处的任何代码
});
// 定时器执行操作方法
- (void)updateTimer {
static int num = 0;
num++;
// 满足条件后,停止当前的运行循环
if (num == 8) {
// 停止当前的运行循环
/*
一旦停止了运行循环,后续代码能够执行,执行完毕后,线程被自动销毁
*/
CFRunLoopStop(CFRunLoopGetCurrent());
}
}
5. 定时器的销毁
在官方文档中我们可以看到 [timer invalidate]是唯一的方法将定时器从循环池中移除。
如果我们启动了一个定时器,在某个界面释放前,将这个定时器停止,甚至置为nil,都不能是这个界面释放,原因是系统的循环池中还保有这个对象,我们需要在下面三个方法中
定时器执行方法
视图显示
ViewDidDisappera
方法deallock
方法
实现如下代码进行定时器的彻底释放:
if (timer.isValid) {
[timer invalidate];
}
timer=nil;
6. 其他实现定时功能的方法
-
performSelector 延时调用
/* 1.5 秒后自动调用 self 的 hideHUD 方法 */ [self performSelector:@selector(hideHUD) withObject:nil afterDelay:1.5]; // 取消延时调用 [NSObject cancelPreviousPerformRequestsWithTarget:self selector:@selector(hideHUD) object:nil];
-
GCD 多线程
/* 1.5 秒后自动执行 block 里面的代码 */ dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(1.5 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ self.hud.alpha = 0.0; });
3. NSTimer 定时器
```
/*
1.5 秒后自动调用 self 的 hideHUD 方法
*/
[NSTimer scheduledTimerWithTimeInterval:1.5
target:self
selector:@selector(hideHUD)
userInfo:nil
repeats:NO];
```