- 在平时开发中,多多少少都会用到定时器,获取短信验证码、商品秒杀倒计时等等,如果每次都去写一堆定时器代码不仅麻烦而且如果操作不慎还会造成内存泄漏;所以,封装一个简单好用+安全+高性能的定时器是非常有必要的。
- 在业余时间我封装了
CJJTimer
,关于定时器的选用,iOS目前为我们提供了NSTimer
,CADisplayLink
,GCD
三种定时器,关于他们的区别和用法本文不再阐述,网上可以找到一堆介绍得非常详细的文章,而CJJTimer
采用了GCD
定时器 - GCD定时器主要优点:准时,高性能
-
demo
模仿淘宝,京东,苏宁易购,拼多多首页倒计时的UI以及简单的短信倒计时效果,这些是通过CJJTimer
来绘制的,直接上图看效果
CJJTimer
CJJTimer
是一个简单好用的定时器工具(适用于短信倒计时、商品秒杀倒计时等等常见场景)
github地址
https://github.com/JimmyCJJ/CJJTimer
文件结构
How To Add CJJTimer?
- 手动管理
下载demo,直接把demo里的文件夹CJJTimer拖进工程即可
- CocoaPods管理
pod 'CJJTimer'
#import
在需要用到的地方导入对应的头文件
#import
How To Use CJJTimer?
CJJTimer
主要有两大模块
- 一个是
CJJTimerView
,用于处理时间(天时分秒、时分秒、时分、分秒)倒计时 - 另一个是
CJJSMSTimer
,用于处理短信倒计时
CJJTimerView
拿上图中的淘宝倒计时做例子
我们把倒计时view
放在cell
里面
- 1.在
cell
里持有CJJTimerView
@property (nonatomic, strong) CJJTimerView *timer;
- 2.懒加载配置
CJJTimerView
通过一个配置类CJJTimerViewConfiguration
配置好所有的功能和UI属性,直接赋给CJJTimerView
即可,任意时机设置timerLastTime
(时间戳,假设现在是7月26号中午12:00,我想要倒数到第二天也就是7月27号的中午12:00,那么就把timerLastTime
设置为第二天的中午12:00的对应时间戳,一般由后台返回)即可自动转换成到目标时间戳的剩余时分秒
支持链式语法调用
- (CJJTimerView *)timer{
if(!_timer){
CJJTimerViewConfiguration *configuration = [CJJTimerViewConfiguration configureTimerView];
configuration.viewWidth(18)
.viewHeight(18)
.hiddenWhenFinished(NO)
.lastTime([NSString stringWithFormat:@"%ld",[self getNowTimeTimeStampSec].integerValue+10])
.cornerRadius(3)
.backgroundColor([UIColor colorWithRed:238/255.0 green:39/255.0 blue:5/255.0 alpha:1])
.textLabelFont([UIFont systemFontOfSize:11 weight:UIFontWeightBold])
.textLabelColor([UIColor whiteColor])
.colonLabelFont([UIFont systemFontOfSize:11 weight:UIFontWeightBold])
.colonLabelColor([UIColor colorWithRed:238/255.0 green:39/255.0 blue:5/255.0 alpha:1]);
_timer = [CJJTimerView timerViewWithConfiguration:configuration];
_timer.delegate = self;
}
return _timer;
}
- 3.布局
CJJTimerView
提供一个接口返回配置好的CJJTimerView的宽和高
/// 自动布局
/// @param layout 此block会返回自动计算后的timerView的width和height,可用于布局
- (void)configureLayout:(CJJTimerViewLayout)layout;
然后只需要配置x和y的布局即可(此处不需要weakSelf,内部不持有block,不存在循环引用)
[self.timer configureLayout:^(CGFloat timerWidth, CGFloat timerHeight) {
[self.timer mas_makeConstraints:^(MASConstraintMaker *make) {
make.left.mas_equalTo(self.titleL.mas_right).offset(5);
make.centerY.mas_equalTo(0);
make.size.mas_equalTo(CGSizeMake(timerWidth, timerHeight));
}];
}];
- 4. 开启倒计时
默认开启定时器
/// 是否自动开启定时器,默认YES
@property (nonatomic, assign, getter=isTimerAutoStart) BOOL timerAutoStart;
如果想手动开启,配置时把该属性设为NO
configuration.timerAutoStart = NO;
然后在适当的时机调用
/// 开启定时器
- (dispatch_source_t)startTimer;
- 5. 销毁倒计时
内部会自动销毁定时器,不需要手动去销毁,如果需要控制销毁的时机的话,也可以调用
/// 销毁定时器(如果想手动控制销毁的时机请调用此方法,否则自动销毁)
- (void)stopTimer;
关于更多细节请直接看demo
CJJSMSTimer
#import
NS_ASSUME_NONNULL_BEGIN
typedef void (^CJJSMSTimerVoidBlock)(void);
typedef void (^CJJSMSTimerSecBlock)(int sec);
@interface CJJSMSTimer : NSObject
/// 开启倒计时 - 完全自定义回调
/// @param btn 传入按钮对象
/// @param timeOut 传入倒数总时间
/// @param ingBlock 倒数进行时的设置
/// @param finishedBlock 倒数结束后的设置
+ (instancetype)timerStartCountdownWithBtn:(UIButton *)btn
timeOut:(int)timeOut
titleIngSettingBlock:(CJJSMSTimerSecBlock __nullable)ingBlock
titleFinishSettingBlock:(CJJSMSTimerVoidBlock __nullable)finishedBlock;
/// 开启倒计时 - 默认回调
/// @param btn 传入按钮对象
/// @param timeOut 传入倒数总时间
/// @param ingTitle 倒数进行时的标题
/// @param ingTitleColor 倒数进行时的标题颜色
/// @param finishedTitle 倒数结束后的标题
/// @param finishedTitleColor 倒数结束后的标题颜色
/// @param ingBlock 倒数进行时的设置
/// @param finishedBlock 倒数结束后的设置
+ (instancetype)timerStartCountdownWithBtn:(UIButton *)btn
timeOut:(int)timeOut
ingTitle:(NSString *)ingTitle
ingTitleColor:(UIColor *)ingTitleColor
finishedTitle:(NSString *)finishedTitle
finishedTitleColor:(UIColor *)finishedTitleColor
titleIngSettingBlock:(CJJSMSTimerSecBlock __nullable)ingBlock
titleFinishSettingBlock:(CJJSMSTimerVoidBlock __nullable)finishedBlock;
/// 销毁定时器(如果想手动控制销毁的时机请调用此方法,否则自动销毁)
- (void)destroyTimer;
@end
- 适用于UIButton,头文件提供2个接口
使用方法
- 1.持有
CJJSMSTimer
@property (nonatomic, strong) CJJSMSTimer *timer;
- 2.在自定义Button的点击事件或者其他时机调用接口提供的方法
- (void)startCountDownAction:(UIButton *)btn{
BOOL isCustom = NO;
//block设置倒计时前后UI变化
if(isCustom){
self.timer = [CJJSMSTimer timerStartCountdownWithBtn:btn timeOut:6 titleIngSettingBlock:^(int sec) {
[btn setTitle:[NSString stringWithFormat:@"%ds",sec] forState:UIControlStateNormal];
[btn setTitleColor:[UIColor grayColor] forState:UIControlStateNormal];
btn.layer.borderColor = [UIColor grayColor].CGColor;
} titleFinishSettingBlock:^{
[btn setTitle:@"获取验证码" forState:UIControlStateNormal];
[btn setTitleColor:[UIColor blueColor] forState:UIControlStateNormal];
btn.layer.borderColor = [UIColor blueColor].CGColor;
}];
}else{
//默认设置方法
self.timer = [CJJSMSTimer timerStartCountdownWithBtn:btn timeOut:6 ingTitle:@"重新获取" ingTitleColor:[UIColor grayColor] finishedTitle:@"获取验证码" finishedTitleColor:[UIColor blueColor] titleIngSettingBlock:^(int sec) {
btn.layer.borderColor = [UIColor grayColor].CGColor;
} titleFinishSettingBlock:^{
btn.layer.borderColor = [UIColor blueColor].CGColor;
}];
}
}
以上代码展示了两种不同的设置方法,实际使用中选择其中一种方式即可
- 3.定时器销毁
原理同上,内部自动销毁,如有需要手动销毁请调用
/// 销毁定时器(如果想手动控制销毁的时机请调用此方法,否则自动销毁)
- (void)destroyTimer;
具体细节请看demo
2021.06.22 版本更新
CJJTimer 2.0.2
支持天时分秒,支持自动切换类型,取消对第三方布局库Masonry的依赖,优化代码
代码细节中如有不足请随意提出评论,如果有更好的实现方法,欢迎联系我一起交流~