美文网首页
iOS,cell中有倒计时情况的总结

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

作者: 原来是泽镜啊 | 来源:发表于2020-10-30 15:25 被阅读0次

    一.先去网上探索

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

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

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

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

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

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

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

    • timer 的添加和销毁

      image
    • 数据不会重用

    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];
            }
        }
    }
    
    
    • 把倒计时的具体剩余时间和与之对应的indexPath保存起来在字典中
    -(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];
    
    
    • 定时器会执行的方法 (在这个方法中修改模型的倒计时,因为模型决定了cell显示什么数据,所以更改模型之后再去刷新这一行就不会出现数据混乱)
    -(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;
        }
    }
    
    

    总结:

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

    • 在控制器中创建timer定时器,一个定时器管理一个cell,如果cell的倒计时结束了,那就停止定时器,而且不会影响到其他cell,也不会浪费性能。
    • 由于修改的是模型,所以避免了数据混乱。
    • 本文 Demo

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

    相关文章

      网友评论

          本文标题:iOS,cell中有倒计时情况的总结

          本文链接:https://www.haomeiwen.com/subject/ujsdvktx.html