综述
NSTimer的初始化有很多种
- 初始化函数:
self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:@selector(Typing)
userInfo:nil
repeats:YES];
- 含义:
定时器启动后,每隔2s中回调一次@selector - 参数
-
scheduledTimerWithTimeInterval:定时时间 -
target:目标,通常设为self -
selector:回调函数,不用解释了 -
userInfo:总是设为nil -
repeats:是否重复
-
- 下面通过代码来说明初始化之后
- 启动定时器
- 终止定时器
- 释放定时器
#import "ViewController.h"
@interface ViewController ()
@property (strong,nonatomic) NSTimer *timer;
@property (nonatomic) NSUInteger count;
@property (weak, nonatomic) IBOutlet UILabel *label;
@end
// -------- 实现 -----------
@implementation ViewController
-(void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.count = 0;
}
-(IBAction)start:(UIButton *)sender {
if (!self.timer) {
self.timer = [NSTimer scheduledTimerWithTimeInterval:2.0
target:self
selector:@selector(Typing)
userInfo:nil
repeats:YES];
}
NSLog(@"%@",self.timer);
[self.timer fire];
}
-(IBAction)stop:(UIButton *)sender {
NSLog(@"<><><><><<><><>>>>>>>>>>>>>>>>>>>>>>>\n%@",self.timer);
[self.timer invalidate];
// self.timer = nil;
NSLog(@"<><><><><<><><>>>>>>>>>>>>>>>>>>>>>>>\n%@",self.timer);
}
-(void)Typing{
self.count ++;
self.label.text = [NSString stringWithFormat:@"fuck %lu",self.count];
}
-(void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
@end
定时器和Runloop —— 待完善
启动定时器除了使用 [self.timer fire]外也可以用Runloop来做。不过具体含义还不清楚
self.timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(typing)
userInfo:nil
repeats:YES];
// [self.timer fire];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
[[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0]];
先说初始化和启动定时器
- 初始化定时器
- 必须先判断定时器是否存在。否则会同时创建N个定时器
2016-01-23 11:09:37.283 TestForTimer[7792:548179] <__NSCFTimer: 0x7f84e9c09920>
2016-01-23 11:09:37.626 TestForTimer[7792:548179] <__NSCFTimer: 0x7f84e9e185f0>
2016-01-23 11:09:37.837 TestForTimer[7792:548179] <__NSCFTimer: 0x7f84e9eb89b0>
2016-01-23 11:09:38.004 TestForTimer[7792:548179] <__NSCFTimer: 0x7f84e9d0ae90>
2016-01-23 11:09:38.187 TestForTimer[7792:548179] <__NSCFTimer: 0x7f84e9c0d500>
2016-01-23 11:09:38.338 TestForTimer[7792:548179] <__NSCFTimer: 0x7f84e9e1da70>
- 这样做的后果是,使用
[self.timer invalidate];的时候,只会终止创建的第一个_NSCFTimer: 0x7f84e9c09920>,剩下的定时器仍然在跑,无法终止。 - 开启定时器
[self.timer fire];最好把这个和初始化定时器放在一起。
上面的代码中,如果我一直点击[self.timer fire],定时器不会被新建,但是会从我点击之下开始,重新计时!! - 终止定时器
- 调用
[self.timer invalidate];之后务必将其释放,赋值为nil,这样下次通过事件按钮触发的时候才能创建一个新的定时器
- 调用
综上,定时器的创建和销毁必须是一对一的!
- 创建时,必须判断定时器是否存在!
- 触发时,定时器会重新计时,但是不影响对象的创建和销毁
- 终止定时器,必须将先前创建的定时器销毁!
= nil操作,很重要!
疑问
当 NSTimer 和 NSCondition 一起使用的时候,似乎无法在NSCondition中阻塞线程后去调用定时器,这样做的后果是定时器的回调函数,只执行一次后就停止了。尚不清楚原因
尝试过用GCD另开线程来做NSTimer,也并不管用。
2017.05.05更新
iOS 10后新增了一种快速定义定时器的类方法:
//API_AVAILABLE(macosx(10.12), ios(10.0), watchos(3.0), tvos(10.0));
+ (NSTimer *)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void (^)(NSTimer *timer))block
说明:(感觉这个函数会更方便一些)
和上面传统的描述不同的是,这个类方法,在NSTimer实例化后,并不需要手动去fire.就像函数说明中写的
After interval seconds have elapsed, the timer fires, executing block.
- 只要时间到了,就会去执行
block中的内容。 - 另外要注意的是,block中的参数 timer就是我们定义的这个timer本身。相当于说在block回调中返回这个定义的实例化变量。
self.reconnectTimer = [NSTimer scheduledTimerWithTimeInterval:self.spaceTime repeats:YES block:^(NSTimer * _Nonnull timer) {
// timer和self.reconnectTimer 其实是一回事
}];
下面是代码块示例:
__block NSUInteger count = 0;
self.reconnectTimer = [NSTimer scheduledTimerWithTimeInterval:self.spaceTime repeats:YES block:^(NSTimer * _Nonnull timer) {
if (count > self.reconnectTimes || self.isConneted == YES) {
NSLog(@"计数终止");
count = 0;
[timer invalidate];
} else {
NSLog(@"计数值 = %lu",count);
count += 1;
[self.centralManager connectPeripheral:peripheral options:nil];
}
}];