cell上添加倒计时,以及时差问题的解决

原址 http://www.cnblogs.com/zhangmaliang/p/5102518.html

  最近项目中用到了tableView的多个cell倒计时系统问题,本觉得很简单的一个事,一做发现还没这么简单,就此记录。

  下面方法模拟网络请求返回数据。

  按照常规思路,根据网络请求返回remainTime,封装模型,存到数组中,再在表格代理方法中赋值给cell

  cell中根据传入模型中的remainTime属性,开启定时器每隔1s调用如下方法

  程序一运行发现问题:每当表格滚动时,表格代理方法cellForRowAtIndexPath会不断重复调用,从数组中取得模型赋值给cell,而模型中的remainTime是固定的,于是倒计时系统不断重复开始倒计时。

​  发现问题点,开始着手解决。开始想到的是方法是在控制器中也开启一套定时器系统,当服务器数据remainTime返回时,将其中remainTime大于0s的数据保存在一个字典中,对所有键值对开始倒计时。

  下面方法模拟网络数据返回,对所有remainTime大于0的字段保存到字典self.timerDic中

  控制器中,定时器每隔1s调用方法,对remainTime减一后再覆盖掉原本键值对
 
 
 
  于是,字典self.timerDi中所有键值对的value每隔1s递减1,直到最后value都变为0。在cellForRowAtIndexPath方法中插入如下
 
 

  cell属性model中的remainTime字段从这个一直变化的self.timerDic字典中取值,于是滚动视图时cell获取到的就不是一个固定的remainTime,效果如下

​​

​  此时已经解决了表格滚动时倒计时重复计时问题,但可以看到多次滚动后会造成如上显示错误,这是由于控制器和cell两套定时系统时差而引起的,具体后面分析。

    此路貌似不通,于是我想到了KVO,让cell监听控制器中remainTime的数值变化​

 这方法还真走效,在cell的observeValueForKeyPath中确实能监听到remainTime的数值变化,数值也异常正确,但同时一个重大问题也产生了,由于cell的复用,cell上所显示的倒计时系统相互错乱,试了几种方法都无法解决,放弃。
 

  仔细分析上面倒计时时差原因,发现时差产生是由于定时器调用频率导致。举个场景说明:控制器返回数据时remainTime是10,过了0.9999s后用户滚动表格,此时cell从字典self.timerDic中取到的remainTime仍旧是10,于是cell定时系统的remainTime值比控制器的慢了0.9999s。同理分析也可能快0.9999s,于是可能会引发最多2s的极限误差。

  找到具体原因修改就比较容易了,使用CADisplayLink,一分钟调用60次countDown方法,每次减去1/60s,则最大误差只有2*1/60s,比较准确,能够满足要求

  最后做下适当优化:定时器在主线程工作,调用频率很高,每次调用还要遍历字典对每一个value递减后覆盖旧值,故希望定时器能在后台工作。定时器工作在后台线程时会自动将其注册到后台线程的runloop,而runloop依托线程但并不会自动创建,此时countDown无法接收到事件回调,需要手动生成runloop并保证其不会退出。这里参照AFN中的生成方法,核心代码如下:

 
  刚开始学swift,因工作还在用OC,只能平时练练手了,:上代码为swift版
  github地址:https://github.com/zhangmaliang/CountDown
原文地址:https://www.cnblogs.com/xujiahui/p/6025739.html