利用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 ...
随机推荐
- android dialog设置全屏半透明背景色
style代码如下: <style name="theme_dialog" parent="@android:style/Theme.Dialog"> ...
- php的phar是什么?
phar 要求5.2以上 前言 最近在看composer,是下载了一个composer.phar,然后放到/usr/local/bin目录下,就可以全局使用composer了,然而并不懂phar是什么 ...
- 027_git添加多账号设置
一. 注意事项: (1)公钥文件权限设置问题 现象: Permissions 0644 for '/Users/arunyang/.ssh/id_rsa_ele_me.pub' are too ope ...
- [NOI2015]软件包管理器-树链剖分
#include<bits/stdc++.h> using namespace std; const int maxn = 1e6+5; int n,m; int e,begin[maxn ...
- kali linux networking scanning Cookbok (第三章结尾笔记)
1.Zombie Scanning with Nmap Zombie scans can also be performed with an option in Namp , we can find ...
- Java:Spring @Transactional工作原理
本文将深入研究Spring的事务管理.主要介绍@Transactional在底层是如何工作的.之后的文章将介绍: propagation(事务传播)和isolation(隔离性)等属性的使用 事务使用 ...
- redis-hash操作
hset(name, key, value) # name对应的hash中设置一个键值对(不存在,则创建:否则,修改) # 参数: # name,redis的name # key,name对应的has ...
- Hibernate Envers
一.目的Hibernate Envers的目的是提供应用程序实体数据的历史版本,记录执行数据变更历史. 二.用途Hibernate Envers记录的审计数据,主要用于意外丢失数据找回.审查数据合法性 ...
- 金蝶K/3 跟踪语句_业务单据
跟踪语句_业务单据_BOM select * from t_TableDescription where Ftablename like '%ICBOM%' order by FFieldName o ...
- python数据类型一:字符串
Python 字符串 字符串是 Python 中最常用的数据类型.我们可以使用引号('或")来创建字符串. 创建字符串很简单,只要为变量分配一个值即可.例如: var1 = 'Hello W ...