GCD计时器替换NSTimer

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
复制代码
  1. 避免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];
    }];
}
复制代码
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值