UITableViewCell独立倒计时异常求助:多Cell共用同一倒计时值
解决UITableView每个Cell独立倒计时的问题
我来帮你搞定这个每个Cell独立倒计时的问题~先看看原代码为啥会出现所有Cell显示同一个倒计时的问题:
- 你用了全局的
currHours、currMinute、currSeconds变量,所有Cell都共享这一组值,循环遍历数组时最后一个元素的倒计时会覆盖前面的,自然所有Cell都显示同一个结果。 - 在循环里创建
NSTimer,会生成多个Timer,但最终只有最后一个会正常工作,而且Timer触发时只更新那一组全局变量,没法做到每个时间点独立递减。
要实现每个Cell对应自己的时间独立倒计时,咱们可以用数据模型+单个全局Timer的方案,具体步骤如下:
1. 创建倒计时数据模型
先新建一个CountdownItem类,用来存储每个倒计时的目标时间、剩余时分秒和显示文本,让每个Cell的状态独立:
// CountdownItem.h #import <Foundation/Foundation.h> @interface CountdownItem : NSObject @property (nonatomic, strong) NSDate *targetDate; // 目标倒计时日期 @property (nonatomic, assign) NSInteger remainingHours; @property (nonatomic, assign) NSInteger remainingMinutes; @property (nonatomic, assign) NSInteger remainingSeconds; @property (nonatomic, copy) NSString *displayText; // 原数组里的时间字符串 @property (nonatomic, assign) BOOL isCompleted; // 是否已经倒计时结束 @end // CountdownItem.m #import "CountdownItem.h" @implementation CountdownItem @end
2. 修改ViewController的代码
把原来的全局变量和数组替换成模型数组,用单个Timer统一更新所有模型的剩余时间:
// 替换原来的全局变量 @property (nonatomic, strong) NSMutableArray<CountdownItem *> *countdownItems; @property (nonatomic, strong) NSTimer *countdownTimer; - (void)viewDidLoad { [super viewDidLoad]; // 初始化原时间数组 NSArray *tableData = @[ @"2018-05-16 06:00:00 p", @"2018-05-16 09:00:00 p", @"2018-05-16 11:00:00 p", @"2018-05-17 02:00:00 a", @"2018-05-17 04:00:00 a" ]; // 初始化倒计时模型数组 self.countdownItems = [NSMutableArray array]; NSDateFormatter *dateFormat = [[NSDateFormatter alloc] init]; [dateFormat setDateFormat:@"yyyy-MM-dd hh:mm:ss a"]; for (NSString *timeStr in tableData) { CountdownItem *item = [[CountdownItem alloc] init]; item.displayText = timeStr; item.targetDate = [dateFormat dateFromString:timeStr]; item.isCompleted = NO; // 计算初始剩余时间 [self updateRemainingTimeForItem:item]; [self.countdownItems addObject:item]; } // 启动单个全局Timer,每秒更新一次 self.countdownTimer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(updateAllCountdowns) userInfo:nil repeats:YES]; } // 更新单个模型的剩余时间 - (void)updateRemainingTimeForItem:(CountdownItem *)item { if (item.isCompleted) return; NSDate *currentDate = [NSDate date]; NSTimeInterval timeInterval = [item.targetDate timeIntervalSinceDate:currentDate]; if (timeInterval <= 0) { // 倒计时结束 item.isCompleted = YES; item.remainingHours = 0; item.remainingMinutes = 0; item.remainingSeconds = 0; return; } // 计算时分秒 item.remainingHours = (NSInteger)(timeInterval / 3600); timeInterval = fmod(timeInterval, 3600); item.remainingMinutes = (NSInteger)(timeInterval / 60); item.remainingSeconds = (NSInteger)fmod(timeInterval, 60); } // Timer触发时更新所有模型的剩余时间 - (void)updateAllCountdowns { BOOL allCompleted = YES; for (CountdownItem *item in self.countdownItems) { [self updateRemainingTimeForItem:item]; if (!item.isCompleted) { allCompleted = NO; } } // 刷新TableView [self.tableview reloadData]; // 如果所有倒计时都结束,停止Timer if (allCompleted) { [self.countdownTimer invalidate]; self.countdownTimer = nil; } } - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { static NSString *simpleTableIdentifier = @"Reuse"; SimpleTableViewCell *cell = (SimpleTableViewCell *)[tableView dequeueReusableCellWithIdentifier:simpleTableIdentifier]; if (cell == nil) { NSArray *nib =[[NSBundle mainBundle]loadNibNamed:@"SimpleTableViewCell" owner:self options:nil]; cell=[nib objectAtIndex:0]; } CountdownItem *item = self.countdownItems[indexPath.row]; cell.TimerLabel.text = item.displayText; // 显示剩余时间,注意补零 cell.dynamicTimerLabel.text = [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)item.remainingHours, (long)item.remainingMinutes, (long)item.remainingSeconds]; return cell; } // 记得在ViewController销毁时停止Timer - (void)dealloc { [self.countdownTimer invalidate]; }
关键改进点说明
- 每个倒计时状态都存在独立的
CountdownItem模型里,不会互相干扰。 - 只用一个全局Timer,每秒统一更新所有模型的剩余时间,避免多个Timer导致的性能问题和逻辑混乱。
- 自动判断每个倒计时是否结束,所有倒计时完成后自动停止Timer。
- Cell配置时直接从对应模型取数据,逻辑清晰,不会出现复用问题。
内容的提问来源于stack exchange,提问作者shiwani
相关产品推荐
相关产品推荐

