利用GCD 中的 dispatch_source_timer 给tableViewCell添加动态刷新的计时/倒计时功能
1、思路一(失败)
在设置好cell 里的内容之后在每个cell 返回时调用定时器事件,更新cell 内容,然后刷新整个表格。
- (void)didadida:(UITableViewCell *)cell indexPath:(NSIndexPath*)indexPath{
    __weak typeof(self) weakSelf = self;
    if (@available(iOS 10.0, *)) {
        self.timer = [NSTimer timerWithTimeInterval:1.0 repeats:YES block:^(NSTimer * _Nonnull timer) {
            cell.textLabel.text = weakSelf.arrM[indexPath.row];
        }];
        [[NSRunLoop mainRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes];
    } else {
        // Fallback on earlier versions
    }
}
简单粗暴不奏效。
1、一秒刷新一次整个表格是不现实的,如果定时器更新频率为一秒60次呢?显然不合理
2、需要管理Timer,Timer的销毁时机不确定。
2、利用GCD的 dispatch_source_create 一个 DISPATCH_SOURCE_TYPE_TIMER
1、假如后台返回的活动结束时间在我们已经格式化为时间戳放在一个数组 self.arrM 里。
2、需要一个格式化时间的方法
3、(重点)每秒更新时间的方法
4、记得销毁定时器
@interface XXX()<UITableViewDelegate, UITableViewDataSource>
@property (nonatomic, strong) dispatch_source_t timer;
@property (nonatomic, strong) NSMutableArray *timestampArr;
@end
//1、viewDidLoad里  self.timestampArr 三个活动结束的时间格式化为时间戳后放在数组里
NSArray *dateTimeArr = @[@"2019-04-15 17:30:00", @"2019-04-15 18:30:00", @"2019-04-15 20:30:00"];
    [dateTimeArr enumerateObjectsUsingBlock:^(id  _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) {
        NSInteger tempTimestamp = [NSString timeToTimestamp:(NSString *)obj andFormatter:@"YYYY-MM-dd HH:mm:00"];
        [self.timestampArr addObject:@(tempTimestamp)];
    }];
//把活动结束时间戳和tableView 传递给目标更新函数,正常逻辑是在请求服务器返回时间列表后更新这些数据
    [self countPerSecond:self.tableView dataList:self.timestampArr];
//返回cell函数里
- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellIDT];
    if (!cell) {
        cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIDT];
    }
    cell.textLabel.text = [self caculateNowTime:[NSString getNowTimestamp] activeStartTime:[self.timestampArr[indexPath.row] longLongValue]];
    cell.tag = indexPath.row;
    cell.textLabel.textColor = [UIColor blackColor];
    NSLog(@"cell text: %@",self.timestampArr[indexPath.row]);
    return cell;
}
/**
 2 计算倒计时时间
 @param nowTime 现在的时间
 @param startTime 活动开始时间
 @return 根据距离活动时间的长短格式化时间显示
 */
- (NSString *)caculateNowTime:(NSInteger)nowTime activeStartTime:(NSInteger)startTime {
    NSTimeInterval timeInterval = nowTime - startTime;
    int days = (int)(timeInterval/(3600*24));
    int hours = (int)((timeInterval - days*24*3600)/3600);
    int minutes = (int)(timeInterval - days*24*3600 - hours*3600)/60;
    int seconds = timeInterval - days*24*360 - hours*3600 - minutes*60;
    NSString *dayStr, *hoursStr, *minutesStr, *secondStr;
    dayStr = [NSString stringWithFormat:@"%d",days];
    hoursStr = [NSString stringWithFormat:@"%d",hours];
    if (minutes < 10) {
        minutesStr = [NSString stringWithFormat:@"0%d",minutes];
    }else {
        minutesStr = [NSString stringWithFormat:@"%d",minutes];
    }
    if (seconds < 10) {
        secondStr = [NSString stringWithFormat:@"0%d",seconds];
    }else {
        secondStr = [NSString stringWithFormat:@"%d",seconds];
    }
    if (days) {
        return [NSString stringWithFormat:@"%@天 %@小时 %@分 %@秒",dayStr, hoursStr, minutesStr, secondStr];
    }
    return [NSString stringWithFormat:@"%@小时 %@分 %@秒",hoursStr,minutesStr,secondStr];
}
//3每秒更新时间
- (void)countPerSecond:(UITableView *)tableView dataList:(NSArray *)dataList {
    if (_timer == nil) {
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        _timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, queue);
        dispatch_source_set_timer(_timer, dispatch_walltime(NULL, 0), 1.0 * NSEC_PER_SEC, 0);
        dispatch_source_set_event_handler(_timer, ^{
            dispatch_async(dispatch_get_main_queue(), ^{
                NSArray *cells = tableView.visibleCells;
                for (UITableViewCell *cell in cells) {
                    NSDate *phoneTime = [NSDate date];
                    NSInteger phoneTimeInteger = [phoneTime timeIntervalSince1970];
                    NSString *tempEndTime = dataList[cell.tag];
                    NSInteger endTime = tempEndTime.longLongValue;//
                    cell.textLabel.text = [self caculateNowTime:endTime activeStartTime:phoneTimeInteger];
                    if ([cell.textLabel.text isEqualToString:@"活动已结束!"]) {
                        cell.textLabel.textColor = [UIColor redColor];
                    }else {
                        cell.textLabel.textColor = [UIColor orangeColor];
                    }
                }
            });
        });
        dispatch_resume(_timer);
    }
}
//4
- (void)destoryTimer {
    if (_timer) {
        dispatch_source_cancel(_timer);
        _timer = nil;
    }
}
这样的思路是可以走通的,但是还有许多需要优化的地方,如由于用的是时间差,计时数据可能是负的。
还有,如果用户改变了,自己手机的时间。我们再获取手机时间和结束时间做差也是不准确的,恶意用户可能用这个漏洞。
针对用户改变手机时间,我们可以在应用从后台进入前台时从新从后台获取一次活动结束时间。
时间,时间戳的转化函数
/**
 获取当前时间戳
 @return 当前时间戳
 */
+ (NSInteger)getNowTimestamp {
    //设置时间格式
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateStyle:NSDateFormatterMediumStyle];
    [formatter setTimeStyle:NSDateFormatterShortStyle];
    [formatter setDateFormat:@"YYYY-MM-dd HH:mm:ss"];
    //设置时区
    NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"Asia/Beijing"];
    [formatter setTimeZone:timeZone];
    NSDate *dateNow = [NSDate date];
    NSLog(@"设备当前的时间:%@",[formatter stringFromDate:dateNow]);
    //时间转时间戳
    NSInteger timeStamp = [[NSNumber numberWithDouble:[dateNow timeIntervalSince1970]] integerValue];
    NSLog(@"设备当前时间戳:%ld",(long)timeStamp);
    return timeStamp;
}
/**
 时间转时间戳
 @param formatTime 格式化的时间字符串
 @param format 时间格式
 @return 时间戳
 */
+ (NSInteger)timeToTimestamp:(NSString *)formatTime andFormatter:(NSString *)format {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateStyle:NSDateFormatterMediumStyle];
    [formatter setTimeStyle:NSDateFormatterShortStyle];
    [formatter setDateFormat:format];
    NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"Asia/Beijing"];
    [formatter setTimeZone:timeZone];
    NSDate *date = [formatter dateFromString:formatTime];
    //时间转时间戳的方法
    NSInteger timestamp = [[NSNumber numberWithDouble:[date timeIntervalSince1970]] integerValue];
    NSLog(@"将某个时间转化成时间戳 : %ld",(long)timestamp);
    return timestamp;
}
/**
 时间戳转字符串
 @param timestamp 时间戳
 @param format 输出的时间格式
 @return 时间
 */
+ (NSString *)timeStampToTime:(NSInteger)timestamp andFormatter:(NSString *)format {
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateStyle:NSDateFormatterMediumStyle];
    [formatter setTimeStyle:NSDateFormatterShortStyle];
    [formatter setDateFormat:format];
    NSTimeZone *timeZone = [NSTimeZone timeZoneWithName:@"Asia/Beijing"];
    [formatter setTimeZone:timeZone];
    NSDate *dateTime = [NSDate dateWithTimeIntervalSince1970:timestamp];
    NSLog(@"time : %@", dateTime);
    NSString *timeStr = [formatter stringFromDate:dateTime];
    return timeStr;
}
参考 https://www.jianshu.com/p/85909aabf058
利用GCD 中的 dispatch_source_timer 给tableViewCell添加动态刷新的计时/倒计时功能的更多相关文章
- 两种利用GCD实现分步获取结果的方式和SDWebImage缓存机制的验证
		前段时间写界面,因为数据的请求分成了两部分,所以用到了多线程,实现数据的分步请求,然后自己写了一个Demo,用两种方式实现分步获取内容,其中也包含了验证SDWebImage这个库的缓存机制,在这里给大 ... 
- 如何利用excel中的数据源制作数据地图
		关于这个问题,制作数据地图的方法已不新奇,总体来说有这么几类方案: 一类方案:直接在excel里制作 优势:个人小数据量应用较为方便简单 缺点:需要熟悉VBA,且更强大的功能对VBA水平要求较高 1. ... 
- iOS 关于GCD中的队列
		GCD中队列分类及获得方式 1.串行队列 dispatch_queue_t queue = dispatch_queue_create("队列名", DISPATCH_QUEUE ... 
- 利用Python中的mock库对Python代码进行模拟测试
		这篇文章主要介绍了利用Python中的mock库对Python代码进行模拟测试,mock库自从Python3.3依赖成为了Python的内置库,本文也等于介绍了该库的用法,需要的朋友可以参考下 ... 
- iOS:对GCD中 同步、异步、并行、串行的见解
		1.GCD-同步执行多线程时 GCD中不管向什么类型的队列加同步任务,实际上都会加到当前线程中(一般为主线程). 2.GCD-异步执行多线程时 GCD中不管向什么类 ... 
- 在Spring-boot中,为@Value注解添加从数据库读取properties支持
		一般我们会把常用的属性放在工程的classpath文件夹中,以property,yaml或json的格式进行文件存储,便于Spring-boot在初始化时获取. @Value则是Spring一个非常有 ... 
- QTabWidget 中 关于Tab 关闭和添加的基本教程!
		QTabWidget是PyQt5 中使用较为广泛的容器之一,经常会在日常使用的软件中用到它:QTabwidget是由几个标签组成,每个标签可以当作一个界面,下面就是应用Qtabwidget的一个简单例 ... 
- 数据库中老师学生家长表添加自动同意好友自动(AgreeAddingFriend ),默认为True
		数据库中老师学生家长表添加自动同意好友自动(AgreeAddingFriend ),默认为True alter table Sys_User add AgreeAddingFriend bit alt ... 
- asp.net中的ListBox控件添加双击事件
		问题:在Aspx页里的ListBox A中添加双击事件,将选中项添加到另一个ListBox B中,双击ListBox B中的选中项,删除当前选中项 页面: <asp:ListBox ID=&qu ... 
随机推荐
- codeblocks更改颜色主题
			链接:http://www.cnblogs.com/wenbosheng/p/5899483.html 
- Pycharm工具导入requests包(python新手)
			在学习使用python的过程中选择了工具Pycharm,但是如下代码: ,起初导包一直报错,解决办法:File->Setting 点击右上角+号,打开搜素对话框 搜素需要的导包,并加入即可解决此 ... 
- linux服务器安装Mysql后,只能看到information_schema/test这两个库,无法修改密码
			参考链接:https://www.cnblogs.com/ThinkVenus/p/7670722.html 问题背景:登录mysql失败,密码错误,由此想到需要更改密码 然而,进入数据库后,只能看到 ... 
- windows :config windows update … 一直处于假死状态
			参考文章:http://www.cnblogs.com/teacat/p/9204225.html 环境:win7 64bit 旗舰版 问题:重启后,系统更新到35%后,一直处于假死状态,未能正确进入 ... 
- 拓扑排序(Topological Sorting)
			一.什么是拓扑排序 在图论中,拓扑排序(Topological Sorting)是一个有向无环图(DAG, Directed Acyclic Graph)的所有顶点的线性序列.且该序列必须满足下面两个 ... 
- linux 乌班图 nginx php直接下载下来
			location ~ \.php(.*)$ { include snippets/fastcgi-php.conf; # # # With php-fpm (or other unix sockets ... 
- jquery 查找子窗口
			$("#订单信息").contents().find('div.datagrid-body').hide();$("#订单信息").contents().fin ... 
- 加密:HashUtils,RSAUtil,AESUtils
			import java.security.MessageDigest; public class HashUtils { public static String getMD5(String sour ... 
- Linux extmail的邮件服务器搭建
			注:本文来源于<extmail搭建> 一.背景介绍 ExtMail Solution 是一个基于优秀开源软件的电子邮件系统解决方案,核心部件包括了Postfix.Amavisd-new.C ... 
- 剑指offer字符串列表
			字符串 面试题5:替换空格 面试题20:表示数值的字符串 面试题58:翻转字符串 面试题58(二):左旋转字符串 
