1.问题描述
使用NSTimer,repeats参数传YES的时候,可能导致Timer不能及时释放,如:
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:weakSelf selector:@selector(timerTick:) userInfo:nil repeats:YES];复制代码
此时,假如持有timer的是UIView对象self,self不能调用Dealloc释放。所以,在需要释放self的时候,需要先手动销毁计时器timer。
- (void)dealloc { //即使将timer的target设置为weakSelf,也不会进入此方法,进行释放 [self destroyTimer];}复制代码
2.使用GCD计时器替换NSTimer可以解决以上问题
头文件
#import@interface TTTimer : NSObject/** 计时器总时长 */@property (nonatomic, assign) NSInteger duration;/** 钟摆间隔 */@property (nonatomic, assign) NSInteger tickInterval;/** 倒计时 */- (void)tickDownProgress:(void(^)(void))progress;- (void)tickDownCompletion:(void(^)(void))completion;- (void)suspend;- (void)resume;- (void)destroy;@end复制代码
实现文件
#import "TTTimer.h"@interface TTTimer () { BOOL _isTickComplete; BOOL _isSuspend;}@property (nonatomic, strong) dispatch_source_t timer;@end@implementation TTTimer- (instancetype)init { if (self = [super init]) { _duration = 0; _tickInterval = 0; _isTickComplete = NO; _isSuspend = YES; } return self;}- (void)tickDownProgress:(void(^)(void))progress { if(self.duration == 0) return; if (!self.timer) { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); dispatch_source_set_timer(self.timer, dispatch_walltime(NULL, 0), self.tickInterval * NSEC_PER_SEC, 0); dispatch_source_set_event_handler(self.timer, ^{ if (progress) { dispatch_async(dispatch_get_main_queue(), ^{ progress(); }); } }); [self resume]; }}- (void)tickDownCompletion:(void(^)(void))completion { if(self.duration == 0) return; __block NSInteger timeOut = self.duration; if (!self.timer) { dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0); self.timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue); dispatch_source_set_timer(self.timer, dispatch_walltime(NULL, 0), self.tickInterval * NSEC_PER_SEC, 0); dispatch_source_set_event_handler(self.timer, ^{ if (timeOut <= 0) { [self destroy]; if(completion) { dispatch_async(dispatch_get_main_queue(), ^{ completion(); }); } _isTickComplete = YES; }else { timeOut = timeOut - self.tickInterval; } }); [self resume]; }}- (void)suspend { if (self.timer && !_isSuspend) { dispatch_suspend(self.timer); _isSuspend = YES; }}- (void)resume { if (self.timer && _isSuspend) { dispatch_resume(self.timer); _isSuspend = NO; }}- (void)destroy { if (self.timer) { if (!_isTickComplete) { [self resume]; } dispatch_source_cancel(self.timer); self.timer = nil; }}@end复制代码
- 避免Block循环引用
- (void)setupTimer { __weak typeof(self) weakSelf = self; self.toolTimer = [[TTTimer alloc] init]; self.toolTimer.tickInterval = 1; self.toolTimer.duration = 5; [self.toolTimer tickDownCompletion:^{ [weakSelf doSomething]; }];}复制代码