利用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 ...
随机推荐
- Kotlin 的优缺点
从Android 7.0开始,谷歌使用的API从Oracle JDK切换到了open JDK,这对于谷歌来说是一个艰难的决定.对于开发者来说,却倍感兴奋,这意味着长期的官司问题也许就此结束,Andro ...
- C++设计模式——解释器模式
解释器模式 在GOF的<设计模式:可复用面向对象软件的基础>一书中对解释器模式是这样说的:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子.如 ...
- Python爬虫实战一之爬取QQ音乐
一.前言 前段时间尝试爬取了网易云音乐的歌曲,这次打算爬取QQ音乐的歌曲信息.网易云音乐歌曲列表是通过iframe展示的,可以借助Selenium获取到iframe的页面元素, 而QQ音乐采用的是 ...
- Xshell出现‘The remote SSH server rejected X11 forwarding request’解决办法
当准备用Xshell进行远程连接的时候出现下面的情况: 那么跟着我来点击鼠标就ojbk了: 文件--->属性--->隧道 然后找打 把那个单选框的对号勾掉,然后点击确认就OK了!!
- Deepin debian安装Libreoffice
Libreoffice LibreOffice 是一款功能强大的办公软件,默认使用开放文档格式 (OpenDocument Format , ODF), 并支持 .docx, .xlsx, *.ppt ...
- Python 回溯算法
回溯算法(试探法) 在搜索尝试过程中寻找问题的解,当发现已不满足求解条件时,就"回溯"返回,尝试别的路径.回溯法是一种选优搜索法,按选优条件向前搜索,以达到目标.但当探索到某一步时 ...
- C# 深拷贝对象实现
public class DeepCopyHelper { //三种深拷贝方法 public static T DeepCopyByReflect<T>(T obj) { //如果是字符串 ...
- Python实现简单的HttpServer
要写一个类似tomcat的简易服务器,首先需弄清楚这几点: 1. 客户端(Client)和服务端(Server)的角色及作用 角色A向角色B请求数据,这时可以把A视为客户端,B视为服务端.客户端的主要 ...
- [转]国家税务总局:个税专项附加扣除APP正式启用!(附操作指南)
https://wallstreetcn.com/articles/3462504 12月31日国家税务总局官网消息,个人所得税专项附加扣除政策将于2019年1月1日起实施.2018年12月31日,由 ...
- SQLServer中的CTE通用表表达式
开发人员正在研发的许多项目都涉及编写由基本的 SELECT/FROM/WHERE 类型的语句派生而来的复杂 SQL 语句.其中一种情形是需要编写在 FROM 子句内使用派生表(也称为内联视图)的 Tr ...