1. 左边是输出台,右边是tableView,点击后modal了一个控制器,停止了计时器

一、主要功能

对于tableViewCell中,总会碰见有多个cell随机计时的问题,于是写了一个工具类。
里面封装了停止倒计时和开始倒计时。提供了倒计时的单位计时时间,以及距离当前时间还剩多长时间开始及时的变量,使用方便,异步线程计算。性能一般。


二、头文件.h

1. 创建方法

1.用着两个方法进行创建,需要的外部参数已经注明,内部对这些参数进行了储存

/*** 请用这个方法(或者对应的init方法)创建对象* @parma countDownStartTime 剩多长时间开始倒计时* @parma countDownUnit 倒计时单位时间* @parma modelArray 需要倒计时的model数组* @parma modelDateKey model储存到期时间的属性名* @parma modelCountDownKey model储存剩余时间的属性名* @parma modelDateType model中储存的到期时间是否为剩余时间*/
-(instancetype)initWithCountDownStartTime: (long)countDownStartTime andCountDownUnit: (double)countDownUnit andModelArray: (NSArray *)modelArray andModelDateKey: (NSString *)modelDateKey andModelCountDownKey: (NSString *)modelCountDownKey andModelDateType: (PYContDownManagerModelDateType)modelDateType;
/*** 请用这个方法(或者对应的init方法)创建对象* @parma countDownStartTime 剩多长时间开始倒计时* @parma countDownUnit 倒计时单位时间* @parma modelArray 需要倒计时的model数组* @parma modelDateKey model储存到期时间的属性名* @parma modelCountDownKey model储存剩余时间的属性名* @parma modelDateType model中储存的到期时间是否为剩余时间*/
+(instancetype)countDownManagerWithCountDownStartTime: (long)countDownStartTime andCountDownUnit: (double)countDownUnit andModelArray: (NSArray *)modelArray andModelDateKey: (NSString *)modelDateKey andModelCountDownKey: (NSString *)modelCountDownKey andModelDateType: (PYContDownManagerModelDateType)modelDateType;

2. 常用的方法:

  1. 这个方法是用于外界进行UI界面刷新的。在这里面可以进行model数组的遍历,找出小于0的model,在做相关UI操作(默认回到了主线程)
/***没次单位时间过后就会掉一次,可以在这里刷新UI(已经回到了主线程)*@param countdownDataFredbackWithBlock 给外界提供了model (这时候model已经赋值成功了),*/
-(void)countdownDataFredbackWithBlock: (void(^)(id model,long long CountDown))countdownDataFredbackWithBlock;
  1. 取消定时器:在大多数情况下,点击cell后会跳转到相应的二级界面,那么我们就有必要把定时器关掉
/***取消定时器*/
-(void)cancelTimer;
  1. 定时器的重启: 同样,在回调到当前界面的时候,定时器应该是重新开启的(其实内部是重新创建了一个定时器)
/***开启定时器*/
-(void)resumeTimer;

3.常用的属性

1.很多情况下,服务器请求回来的时间与本地时间并不一致,这样会导致倒计时的不准确,所以我们要把本地参考的当前时间与服务器的当前时间作统一,把服务器时间传入这里,就可以来更正倒计时的准确度
如果对服务器与客户端时间矫正问题有疑问请看这里

/*** 客户端时间,默认为手机的当前时间。如果有偏差可以在这里调整*/
@property (nonatomic,strong) NSDate *clientTime;

三、具体实现的逻辑.m

1. 逻辑

  1. 类的内部创建了一个定时器。每次定时器执行后都会遍历model数组,并且判断是否应该倒计时,如果需要倒计时,那么就通过kvc给model的剩余时间属性赋值。
  2. 每隔一个单位时间间隔,就会执行回调方法的block
  3. 根据对model数组的遍历生成IndexPath,并且对外界暴露出去,从而进行UI的刷新,

2. 具体实现
1. 创建对象

其实就是记录了一下属性并且最后用 [self createTimer]创建了一个定时器

#pragma mark - 创建对象
+(instancetype)countDownManagerWithCountDownStartTime: (long)countDownStartTimeandCountDownUnit: (double)countDownUnitandModelArray: (NSArray *)modelArrayandModelDateKey: (NSString *)modelDateKeyandModelCountDownKey: (NSString *)modelCountDownKeyandModelDateType: (PYContDownManagerModelDateType)modelDateType
{return [[self alloc]initWithCountDownStartTime:countDownStartTimeandCountDownUnit:countDownUnitandModelArray:modelArrayandModelDateKey:modelDateKeyandModelCountDownKey:modelCountDownKeyandModelDateType:modelDateType];
}
-(instancetype)initWithCountDownStartTime: (long)countDownStartTimeandCountDownUnit: (double)countDownUnitandModelArray: (NSArray *)modelArrayandModelDateKey: (NSString *)modelDateKeyandModelCountDownKey: (NSString *)modelCountDownKeyandModelDateType: (PYContDownManagerModelDateType)modelDateType
{self = [super init];if (self) {self.countDownStartTime = countDownStartTime;self.countDownUnit = countDownUnit;self.modelArray = modelArray;self.modelDateKey = modelDateKey;self.modelCountDownKey = modelCountDownKey;self.modelDateType = modelDateType;if (!self.timer){[self createTimer];}}return self;
}
  1. 定时器的创建

这里用了GCD的定时器,子线程进行了数据的遍历处理,并在主线程进行了计时事件的回调。

//MARK: 计时器的创建
-(void)createTimer {
//0.创建队列dispatch_queue_t queue = self.queue;//1.创建GCD中的定时器/*第一个参数:创建source的类型 DISPATCH_SOURCE_TYPE_TIMER:定时器第二个参数:0第三个参数:0第四个参数:队列*/dispatch_source_t timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);self.timer = timer;//2.设置定时器/*第一个参数:定时器对象第二个参数:DISPATCH_TIME_NOW 表示从现在开始计时第三个参数:间隔时间 GCD里面的时间最小单位为 纳秒第四个参数:精准度(表示允许的误差,0表示绝对精准)*/dispatch_source_set_timer(timer, DISPATCH_TIME_NOW, self.countDownUnit * NSEC_PER_SEC, 0 * NSEC_PER_SEC);//3.要调用的任务dispatch_source_set_event_handler(timer, ^{NSLog(@"GCD-----%@",[NSThread currentThread]);dispatch_async(self.queue, ^{[self lookingForATimelyModelArray:self.modelArray];dispatch_async(dispatch_get_main_queue(), ^{if (self.countdownDataFredbackWithBlock) {self.countdownDataFredbackWithBlock();}});});});//4.开始执行dispatch_resume(timer);
}
  1. 数据的处理

1.这个方法一直在子线程完成,对外界传来的model数组进行了遍历。并且对剩余时间进行了计算

-(void)lookingForATimelyModelArray: (NSArray *)modelArray {[modelArray enumerateObjectsUsingBlock:^(id  _Nonnull model, NSUInteger idx, BOOL * _Nonnull stop) {//如果依然是数组那么就在便利一次if ([[model class] isSubclassOfClass:NSClassFromString(@"NSArray")]) {self.column ++;[self lookingForATimelyModelArray:model];}//判断model中的关于时间类的类型NSString *dateValue = [model valueForKey:self.modelDateKey];long long dateNumber = dateValue.longLongValue;       //如果没有时间值if (!dateNumber) return;        //判断是否需要计算时间差if (self.modelDateType == PYContDownManagerModelDateType_OriginalTime){//时间差计算dateNumber = [self computationTimeDifferenceWithDateNumber:dateNumber];}//判断是否需要计时if (dateNumber <= self.countdownStartTime) {if ([[model valueForKey:self.modelCountDownKey] isKindOfClass:NSClassFromString(@"NSString")]) {[model setValue:@(dateNumber).description forKey:self.modelCountDownKey];}else if ([[model valueForKey:self.modelCountDownKey] isKindOfClass:NSClassFromString(@"NSNumber")]) {[model setValue:@(dateNumber) forKey:self.modelCountDownKey];}}}];
}
//MARK: 时间差的计算
-(long long)computationTimeDifferenceWithDateNumber: (long long)dateNumber {   NSTimeInterval timeInterval = [self.clientTime timeIntervalSince1970];return (dateNumber - timeInterval);
}

4.与外界联系的中转站

外界的传入的block代码块用属性储存,并在每个时间间隔过后调用

//MARK: 外部刷新UI的接口
- (void)countdownDataFredbackWithBlock: (void(^)())countdownDataFredbackWithBlock {self.countdownDataFredbackWithBlock = countdownDataFredbackWithBlock;
}

对model所在的位置IndexPath进行回调给外部,让外部进行UI的刷新

/*** 每个model的剩余值得改变都会调用* @param changeModelBlock 改变model时候的回调*/
- (void)countDownWithChangeModelBlock: (void (^)(id model, NSIndexPath *index)) changeModelBlock;

5.取消与开启定时器

//MARK: 取消定时器
-(void)cancelTimer {dispatch_cancel(self.timer);self.timer = nil;
}
//MARK: 开启定时器
-(void)resumeTimer {if (!self.timer) {[self createTimer];}
}

6.上拉加载的卡顿现象的解决

/*** 在集成了MJRefresh之后,上拉加载时, 会出现卡顿,* 这是因为在子线程计算数据后,在回到主线程刷新UI时候,会强制把runloop由NSDefaultRunLoopMode转化为NSDefaultRunLoopMode,从而MJRefresh会自动回弹,* 此方法主要解决了这个问题。* 传入scrollView监听了偏移量,在滑动到底部的时候,会自动关闭Model的刷新和对外界的UI刷新,*/
-(void)stopWenScrollViewScrollBottomWithTableView: (UIScrollView *)scrollView;

四、使用注意

对于UI的刷新

  1. 如果你要进行外部的TableView的刷新,那么请不要粗暴的reloadData,而是应该根据暴露出的IndexPath进行单一cell的刷新。
  2. 不要通过对cell的label.text的直接修改而达到倒计时的UI显示的效果。因为cell是会被重用的,你在外部拿到的label是一个地址,用这个方法进行刷新,你会发现,数据会错乱的一塌糊涂,毫无规律

上拉加载操作时候的卡顿现象

1.如果你用到的是这个方法进行刷新,那么在上拉操作的时候将不会造成UI的卡顿,但是,这个方法也会造成一些不必要的性能负担。因为大多情况下,其实很多cell 是不需要刷新的。

   //每个单位时间都会调用的方法[self.contDownManager countdownDataFredbackWithBlock:^{[self.tableView reloadData];}];

2.如果你用的这个方法刷新在上拉刷新时,UI界面会出现抽搐现象
““
//根据indexPath进行刷新
[self.contDownManager countDownWithChangeModelBlock:^(id model, NSIndexPath *index) {
//刷新
[self.tableView reloadRowsAtIndexPaths:@[index] withRowAnimation:UITableViewRowAnimationNone];
}];


>3.比较复杂的刷新方法。
`1、在tableView的cell中,定义一个NSString类型的属性countDownString,并对外暴露`
`2、在属性countDownString的setter方法中对显示计时信息的Label赋值 `
具体代码
cell中

[self.contDwonManager countDownWithChangeModelBlock:^(HXBFinHomePageViewModel_PlanList *model, NSIndexPath *index) {
if (weakSelf.finPlanListVMArray.count > index.row) {
HXBFinancting_PlanListTableViewCell *cell = [weakSelf.planListTableView cellForRowAtIndexPath:index];
cell.countDownString = model.countDownString;
}
}];
“`

不懂的话就看示例代码把:源代码请点这里这里

倒计时工具类:PYContDownManager相关推荐

  1. 干货三:CountDownTimer倒计时工具类

    概述 毫无疑问,我们先来看下官方文档中给的介绍 CountDownTimer 官方定义如下: Schedule a countdown until a time in the future, with ...

  2. Android倒计时工具类

    为什么80%的码农都做不了架构师?>>>    原文地址:http://my.oschina.net/reone/blog/710003 多谢touch_ping 的回应.  原来a ...

  3. Android生命周期工具类,Android倒计时工具类

    多谢touch_ping 的回应.  原来api有这个类  android.os.CountDownTimer , 具体实现很下面的差不多. import android.content.Contex ...

  4. flutter倒计时TimerUtil工具类

    更多文章请查看 lutter从入门 到精通 flutter 提供了 Timer 来执行定时任务 common_utils 工具类已经 封装了 Timer 一个计时工具类 TimerUtil,可实现倒计 ...

  5. XX健康:移动端开发-体检预约验证码30秒倒计时短信验证码获取与验证DatePicker日历展示提交预约复杂流程阿里短信工具类

    1. 体检预约流程 用户可以通过如下操作流程进行体检预约: 在移动端首页点击体检预约,页面跳转到套餐列表页面 在套餐列表页面点击要预约的套餐,页面跳转到套餐详情页面 在套餐详情页面点击立即预约,页面跳 ...

  6. CountDownTimer 倒计时,定时器工具类

    CountDownTimer 倒计时,定时器工具类 可以用于各种倒计时控件,或者超时机制,使用十分方便. public class CountDownTimerUtils {/*** 倒计时结束的回调 ...

  7. 三个好用的并发工具类

    转载自  三个好用的并发工具类 以前的文章中,我们介绍了太多的底层原理技术以及新概念,本篇我们轻松点,了解下 Java 并发包下.基于这些底层原理的三个框架工具类. 它们分别是: 信号量 Semaph ...

  8. JavaScript常用工具类整理(总结版)

    导读:在前端开发过程中需要对常用的功能模块进行封装,常用的方法多次调用需要整合,保证组件的复用性与程序的可维护性,这里总结一下,便于后续的使用! 目录 1.全局声明工具类 2.定时器 3.判断变量是否 ...

  9. 线程工具类 - CountDownLatch(倒计时器)

    CountDownLatch官方文档 一.原理 CountDownLatch是一个非常实用的多线程控制工具类.Count Down在英文中意为倒计时,Latch意为门闩,可以简单的将CountDown ...

最新文章

  1. Xamarin XAML语言教程基本页面ContentPage占用面积
  2. Python:docx模块
  3. 设置Dialog全屏显示(转)
  4. 08服务器许可证安装向导,08_安装部署GRID许可证服务器.pdf
  5. Javascript:自定义构造函数的优化
  6. 动手学Pytorch深度学习建模与应用
  7. Linux su 命令
  8. 一个老程序员的计算机视觉蹒跚学习之路
  9. 信息安全之加密域可逆信息隐藏
  10. HIT深入理解计算机系统大作业
  11. 如何搭建一个在线教育平台
  12. 购房贷款 等额本息 等额本金
  13. 算法的时间与空间复杂度(精细+举例)
  14. 用 TFserving 部署深度学习模型
  15. 时隔10年,STM32标准外设库再次升级
  16. 钢铁电商平台的Docker容器云平台建设实践
  17. Chrome浏览器如何完美实现滚动截图技巧
  18. mac c语言 gui,MAC GUI编程编译wxWidgets源码教程
  19. 基于WordPress的Zmovie电影模板源码
  20. 12-4 日期时间类

热门文章

  1. python语言三大基本控制结构_【笔记】《python语言程序设计》——程序的控制结构...
  2. 电信黑莓手机出国漫游注意事项
  3. 电脑蓝牙打电话-总结(五、玖云33e9cloud)
  4. 免费正版杀毒软件集合 有你需要的
  5. android手机怎样开启usb调试模式,Android手机USB调试在哪?安卓手机如何打开USB调试模式?...
  6. solidworks2018安装
  7. kaldi查看不同文件的命令集锦
  8. 基于用户画像的电影推荐系统论文
  9. 登陆表单中添加点击刷新的验证码
  10. docker ubuntu容器安装ping工具