利用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 ...
随机推荐
- 《css网站布局实录》(李超)——读书札记
1.web表现层技术 2.HTML链接设计思想 3.对信息进行合理的分析.分类与处理来创造商业价值. 4.头部描述浏览器所需信息,主体包含所需要展现的具体内容. 5.HTML(XHTML)XML 6. ...
- 前端 $.parseJson()
$.parseJSON() 函数用于将符合标准格式的的JSON字符串转为与之对应的JavaScript对象. 例子: 这里首先给出JSON字符串集,字符串集如下: var data=" { ...
- vCenter Server 6 Standard
准备环境和工具: 三台 ESXi 6.0主机: 准备一台Windows Server 2008 R2系统的虚拟机: VMware-VIM-all-6.0.0.iso 软件下载地址 链接: https: ...
- alembic使用
前言 alembic是SQLAlchemy作者编写的控制 model 版本的模块,配合SQLAlchemy使用更佳 正文 安装 pip install alembic alembic是可以在DOS中执 ...
- JS中 typeof,instanceof类型检测方式
在js中的类型检测目前我所知道的是三种方式,分别有它们的应用场景: 1.typeof:主要用于检测基本类型. typeof undefined;//=> undefined typeof 'a' ...
- 转载:.Net 程序集 签名工具sn.exe 密钥对SNK文件 最基本的用法
.Net 程序集 签名工具sn.exe 密钥对SNK文件 最基本的用法 阐述签名工具这个概念之前,我先说说它不是什么: 1.它不是用于给程序集加密的工具,它与阻止Reflector或ILSpy对程序集 ...
- POJ1321 棋盘问题(简单搜索)
题意: 在一个给定形状的棋盘(形状可能是不规则的)上面摆放棋子,棋子没有区别.要求摆放时任意的两个棋子不能放在棋盘中的同一行或者同一列,请编程求解对于给定形状和大小的棋盘,摆放k个棋子的所有可行的摆放 ...
- 纯css画直角三角形
所有的三角形,都是通过盒子模型来设定. border(边框)的不同大小来决定 border-width: 边框的宽度 border-style: 边框的样式 border-color: 边框的颜色 1 ...
- celery使用
1.常用命令 (1)启动后台职程 celery worker -A tasks --loglevel=info celery worker -A tasks --loglevel= -A 是指cele ...
- Codeforces 455A Boredom (线性DP)
<题目链接> 题目大意:给定一个序列,让你在其中挑选一些数,如果你选了x,那么你能够得到x分,但是该序列中所有等于x-1和x+1的元素将全部消失,问你最多能够得多少分. 解题分析:从小到大 ...