iOS,cell中有倒计时情况的总结

2020-10-30  本文已影响0人  原来是泽镜啊

一.先去网上探索

自己的项目中用到了关于倒计时的功能,请求的列表数据中有些cell是需要显示倒计时的, 之前没有做过这个功能, 以为应该一会儿就搞定了。 事实 上也是一会儿就搞个倒计时的效果出来了,感觉自己萌萌哒, 也就不去管了,可是过了几天测试数据的时候发现了很严重的cell重用问题,倒计时数据会出现错乱。于是开始在网上搜索解决方案,总结了一下大概是这样实现:

遍历请求到的数据源,然后开启定时器,每过一秒就遍历所有数据源,然后把里面的数据更改之后再重新赋值回去。

显而易见,每过一秒就遍历所有的数据源去自减数据很耗性能,而且我的项目中,并不是每个cell里都有倒计时,不需要做这么多多余的操作。

本人5年iOS开发经验,曾就职于阿里巴巴。 善于把艰涩的iOS知识转化为通俗易懂的白话文字,同时也欢迎大家加入小编的iOS交流群 413038000 ,群里会提供相关面试资料,书籍欢迎大家入驻!

而且,我按照其中一种方法写的结果,虽然可以防止重用cell带来的数据混乱,但是快速滚动tableView的时候停下来之后,cell上的数据会有短暂的不对(就是上一个cell的倒计时数据)一秒之后才会变成正确的数据,另一方面定时器的销毁也成了问题,销毁之后全部cell都失去倒计时的功能,完全不符合需求。

二. 结合网上的示例自己的解决方案

基于上面的缺陷,我想到了一个方法可以保证性能消耗不那么大,而且数据也不会出现错乱。而且包括数据的请求,缓存本地,上拉加载和上拉刷新时候带来的倒计时问题。具体源代码可以去github上下载,其实都是很简单的实现方法只是可能之前没有人分享出来,如果你发现代码中的 bug,或者你有更好的方法,欢迎批评指正!
  这里写出核心的思想。如果你的项目和我一样有这些需求,那么可以给你作一个参考。

image

控制器中的代码

-(void)enumerateDatasourceCountDown
{
    for(int i = 0; i < self.dataSource.count; ++i)
    {
        DataModel *model = self.dataSource[i];
        if (model.countTime)
        {
            [self countDownModel:model andIndexPath:i];
        }
    }
}

-(void)countDownModel:(DataModel *)model andIndexPath:(NSInteger )indexInteger
{
    //哪一行的数据有倒计时
    NSString *indexKey = [NSString stringWithFormat:@"%ld",indexInteger];
    NSMutableDictionary *dict = [NSMutableDictionary dictionary];
    [dict setObject:indexKey forKey:@"indexPath"];
    [dict setObject:@(model.countTime) forKey:indexKey];

    //把模型里的倒计时储存在字典中 以行数index索引为key
    //添加定时器之前先判断这一行的数据是不是已经添加了定时器
    NSNumber *number = self.countDownTimeDict[indexKey];
    NSInteger numberInteger =  [number integerValue];

    //如果在倒计时的字典中取不到 value 说明还没有添加定时器
    if (numberInteger <= 0)
    {
        //添加定时器
        NSTimer *timer  =  [NSTimer timerWithTimeInterval:1.0 target:self selector:@selector(numberCutDown:) userInfo:dict repeats:YES];
        [self.timerArr addObject:timer];
        [[NSRunLoop currentRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];

        NSLog(@"第%ld行已经添加了定时器",indexInteger);
    }
    [self.countDownTimeDict addEntriesFromDictionary:dict];

-(void)numberCutDown:(NSTimer *)timer
{
    //取出对应倒计时
    NSString * indexInteger = timer.userInfo[@"indexPath"];
    NSInteger index = [indexInteger integerValue];

    DataModel *model = self.dataSource[index];
    //修改模型时间
    model.countTime --;
    //刷新界面
    NSIndexPath *indexPath = [NSIndexPath indexPathForRow:index inSection:0];
    [self.tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone];
    if (model.countTime == 0)
    {
        NSLog(@"第%ld行的定时器销毁了",index);
        [timer invalidate];
        timer = nil;
        return;
    }
}

总结:

这种方式,是在控制器中每过一秒就修改数据源,然后再重新刷新这一行数据达到倒计时的效果,解决了上述的两个问题。

作者:its程
链接:https://www.jianshu.com/p/a5834f147ef0

上一篇下一篇

猜你喜欢

热点阅读