1. 初始化熙掺,添加定時(shí)器前先移除
[self.timer invalidate];
self.timer = nil;
self.timer = [NSTimer scheduledTimerWithTimeInterval:2.f target:self selector:@selector(lookforCard:) userInfo:nil repeats:YES];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
2. 釋放timer
[self.timer invalidate];
self.timer = nil;
3. NSTimer不釋放原因
- 原因是 Timer 添加到 Runloop 的時(shí)候狭姨,會(huì)被 Runloop 強(qiáng)引用蜕着;然后 Timer 又會(huì)有一個(gè)對(duì) Target 的強(qiáng)引用(也就是 self )
注意target參數(shù)的描述:
The object to which to send the message specified by aSelector when the timer fires. The timer maintains a strong reference to target until it (the timer) is invalidated.
注意:文檔中寫的很清楚,timer對(duì)target會(huì)有一個(gè)強(qiáng)引用宰译,直到timer is invalidated琐谤。也就是說蟆技,在timer調(diào)用 invalidate方法之前,timer對(duì)target一直都有一個(gè)強(qiáng)引用斗忌。這也是為什么控制器的dealloc 方法不會(huì)被調(diào)用的原因质礼。
方法的文檔介紹:
The receiver retains aTimer. To remove a timer from all run loop modes on which it is installed, send an invalidate message to the timer.
也就是說,runLoop會(huì)對(duì)timer有強(qiáng)引用飞蹂,因此几苍,timer修飾符是weak,timer還是不能釋放陈哑,timer的target也就不能釋放妻坝。
4. 解決辦法
-
viewWillDisappear
或viewDidDisappear
中 invalidate
這種方式是可以釋放掉的,但如果我只是想在離開此頁(yè)時(shí)要釋放惊窖,進(jìn)入下一頁(yè)時(shí)不要釋放刽宪,場(chǎng)景就不適用了
- (void)viewWillDisappear:(BOOL)animated
- (void)viewDidDisappear:(BOOL)animated
- 添加一個(gè)NSTimer的分類,把target指給[NSTimer class]界酒,事件由加方法接收圣拄,然后把事件通過block傳遞出來
@interface NSTimer (Block)
+ (instancetype)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void(^)(NSTimer *timer))block;
@end
@implementation NSTimer (Block)
+ (instancetype)scheduledTimerWithTimeInterval:(NSTimeInterval)interval repeats:(BOOL)repeats block:(void(^)(NSTimer *timer))block{
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:interval target:self selector:@selector(trigger:) userInfo:[block copy] repeats:repeats];
return timer;
}
+ (void)trigger:(NSTimer *)timer{
void(^block)(NSTimer *timer) = [timer userInfo];
if (block) {
block(timer);
}
}
@end
- 使用示例
@interface SecondViewController ()
@property (nonatomic, strong) NSTimer *timer;
@end
@implementation SecondViewController
- (void)viewDidLoad {
[super viewDidLoad];
__weak typeof(self) weakSelf = self;
self.timer = [NSTimer scheduledTimerWithTimeInterval:0.5 repeats:YES block:^(NSTimer * _Nonnull timer) {
[weakSelf doSomeThing];
}];
[[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
}
- (void)dealloc {
[self.timer invalidate];
}
@end
5. invalidate方法注意事項(xiàng)
invalidate方法的介紹:
(1)This method is the only way to remove a timer from an NSRunLoop object. The NSRunLoop object removes its strong reference to the timer, either just before the invalidate method returns or at some later point.
(2)You must send this message from the thread on which the timer was installed. If you send this message from another thread, the input source associated with the timer may not be removed from its run loop, which could prevent the thread from exiting properly.
兩點(diǎn):
(1)invalidate方法是唯一能從runloop中移除timer的方式,調(diào)用invalidate方法后毁欣,runloop會(huì)移除對(duì)timer的強(qiáng)引用
(2)timer的添加和timer的移除(invalidate)需要在同一個(gè)線程中庇谆,否則timer可能不能正確的移除岳掐,線程不能正確退出