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 <Foundation/Foundation.h>
@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];
}];
}
复制代码