「这是我参与11月更文挑战的第28天,活动详情查看:2021最后一次更文挑战」
在项目开发过程中无可避免的会使用到计时器的功能, 尤其是在电商和金融项目中居多, iOS中使用计时器,系统提供了 NSTimer
的API来实现.
NSTimer
计时器的功能是, 在指定间隔时间向一个对象发送一条消息, 我们可以配合系统通知来达到广播的效果.
通过用于 定时更新界面 定时刷新请求等等场景, 但是在使用 NSTimer
的过程中, 需要注意的地方很多, 比如强弱引用 内存释放 等问题.
我们针对这些问题来进行了解一下, 避免项目中出现类的问题.
- 内存泄漏
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(update) userInfo:nil repeats:YES];
这段代码有一个问题就是, 导致timer无法释放.
创建一个无限循环的timer, 投入到当前线程的Runloop中, 这个时候Runloop会引用timer, 而timer会引用self, 但是self又持有timer, 这样的情况timer无法释放, 从而导致内存泄漏.
要破解这种情况也很简单, 苹果已经给出了解决的方案, 就是需要显式的调用 [timer invalidate]
, 这样就可以将 timer
释放掉了, 为了安全起见 self.timer = nil;
如此操作 timer
肯定已经释放的干干净净了.
但是调用的时机也是有讲究的, 在我接手的代码里面, 我见到过在 dealloc
里面的调用的, = =
这样的调用肯定是错误的, timer
会引用self, 那么在 timer
释放之前, self是不会释放的, 也就是说不会调用 dealloc
的, 所以这样是错误的.
可以在 viewDidDisappear:
的方法中调用就可以了.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(update) userInfo:nil repeats:YES];
}
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.timer invalidate];
}
还有一个需要注意的地方就是在调用 invalidate
方法之后, 如果 timer
是self最后一个持有target的对象, 那么self也会被销毁掉了, 那么在 invalidate
之后调用 self 的话, 就会造成野指针的错误.
比如如下操作:
- (void)viewDidDisappear:(BOOL)animated {
[super viewDidDisappear:animated];
[self.timer invalidate];
[self.tableView reloadData];
}
self 在调用 invalidate
之后已经销毁了, 那么调用 [self.tableView reloadData];
就会报野指针错误了.
当然计时器的功能也不仅仅只能通过 NSTimer
来实现, 也可以通过 dispatch timer
的方式来实现, 这里就先不展开讲解了, 毕竟这是一篇将 NSTimer
的文章, 后续会有对 dispatch timer
的文章, 谢谢大佬点评.