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添加动态刷新的计时/倒计时功能的更多相关文章

  1. 两种利用GCD实现分步获取结果的方式和SDWebImage缓存机制的验证

    前段时间写界面,因为数据的请求分成了两部分,所以用到了多线程,实现数据的分步请求,然后自己写了一个Demo,用两种方式实现分步获取内容,其中也包含了验证SDWebImage这个库的缓存机制,在这里给大 ...

  2. 如何利用excel中的数据源制作数据地图

    关于这个问题,制作数据地图的方法已不新奇,总体来说有这么几类方案: 一类方案:直接在excel里制作 优势:个人小数据量应用较为方便简单 缺点:需要熟悉VBA,且更强大的功能对VBA水平要求较高 1. ...

  3. iOS 关于GCD中的队列

    GCD中队列分类及获得方式 1.串行队列  dispatch_queue_t queue = dispatch_queue_create("队列名", DISPATCH_QUEUE ...

  4. 利用Python中的mock库对Python代码进行模拟测试

    这篇文章主要介绍了利用Python中的mock库对Python代码进行模拟测试,mock库自从Python3.3依赖成为了Python的内置库,本文也等于介绍了该库的用法,需要的朋友可以参考下     ...

  5. iOS:对GCD中 同步、异步、并行、串行的见解

    1.GCD-同步执行多线程时          GCD中不管向什么类型的队列加同步任务,实际上都会加到当前线程中(一般为主线程). 2.GCD-异步执行多线程时          GCD中不管向什么类 ...

  6. 在Spring-boot中,为@Value注解添加从数据库读取properties支持

    一般我们会把常用的属性放在工程的classpath文件夹中,以property,yaml或json的格式进行文件存储,便于Spring-boot在初始化时获取. @Value则是Spring一个非常有 ...

  7. QTabWidget 中 关于Tab 关闭和添加的基本教程!

    QTabWidget是PyQt5 中使用较为广泛的容器之一,经常会在日常使用的软件中用到它:QTabwidget是由几个标签组成,每个标签可以当作一个界面,下面就是应用Qtabwidget的一个简单例 ...

  8. 数据库中老师学生家长表添加自动同意好友自动(AgreeAddingFriend ),默认为True

    数据库中老师学生家长表添加自动同意好友自动(AgreeAddingFriend ),默认为True alter table Sys_User add AgreeAddingFriend bit alt ...

  9. asp.net中的ListBox控件添加双击事件

    问题:在Aspx页里的ListBox A中添加双击事件,将选中项添加到另一个ListBox B中,双击ListBox B中的选中项,删除当前选中项 页面: <asp:ListBox ID=&qu ...

随机推荐

  1. MapReduce Partition解析

    Map的结果,会通过partition分发到Reducer上,reducer操作过后会进行输出.输出的文件格式后缀000001就代表1分区. Mapper处理过后的键值对,是需要送到Reducer那边 ...

  2. crowdstrike提供的应急响应工具

    下载链接 https://www.crowdstrike.com/resources/community-tools/ CROWDSTRIKE防病毒资源监视器 CrowdStrike Antiviru ...

  3. 用WKWebView 截取整个Html页面

    以前使用UIWebview时,想截取整个页面,可以调整内部scrollView的frame,之后调用 scrollView的layer的 render 方法,很方便. 但是在WKWebView上,行不 ...

  4. html基础技巧:点击、placeholder、文本、字体、清楚浮动

    点击处理: 消除a标签点击后的边框,颜色(background:#fff) 1:a:focus{outline:none;} button去除边框 1:border:none 2:border:0px ...

  5. 关于 layer.mask = label.layer 出现空白情况

    源代码如下: self.numLabel = [[UILabel alloc]initWithFrame:CGRectMake(0, 0, self.view.frame.size.width/3, ...

  6. MySQL批量更新字段url链接中的域名

    1. 首先进行数据库备份 2. SQL语句 UPDATE 表名 SET 字段 = REPLACE(字段, '待更新的内容','替换值'); eg: UPDATE 98k_images SET url ...

  7. 【转】win10哪个版本最好用,推荐win10企业版LTSC

    https://msdn.itellyou.cn/ win10企业版LTSC又被称为win10企业版2019长期服务版本,这个版本小编认为是目前最好用的win10版本,在win10企业版2016长期服 ...

  8. kvm虚拟化2-qemu-kvm

    Kvm  只支持x86 64的硬件虚拟化    要求cpu必须支持硬件虚拟化 HVM Kvm两个组件: 1 kvm.ko模块装入后为/dev/kvm 工作为hypervisor ,在用户空间通过系统调 ...

  9. mysql 删除所有表

    SELECT concat('DROP TABLE IF EXISTS ', table_name, ';')FROM information_schema.tablesWHERE table_sch ...

  10. IDEA中添加servlet的jar

    问题解决:办法1:使用Project Structure 方法二:使用Maven 在pom.xml文件中添加如下