Display StopWatch timer dynamically in UITableViewCell

I want to save the timer values โ€‹โ€‹and display it from the beginning in a new UITableViewCell , but my problem is that I can successfully display the stopwatch timer on the first cell, but when I try to add a new cell to the UITableView , so my timer is set to the second cell, and I canโ€™t determine how to keep my first timer alive.

I was thinking about managing the array, but I want to rewrite TableData every time, but I think this is bad :(

I tried to work as shown below, but I donโ€™t understand how to show timerValue in the previous cell with a working dynamic stopwatch from the same counter and with the new timerValue core from the moment it started.

A static solution, but my rows are dynamically inserted and deleted from the TableView, so the static solution limits me for a certain number of rows and is looking for a dynamic solution.

  - (void) putDelayOnTimeOut { if (!_timerQueue) { _timerQueue = dispatch_queue_create("timer_queue", NULL); } dispatch_async(_timerQueue, ^{ self.startTime = [NSDate date]; if (globalRowIndex == 0) { _timer = [NSTimer scheduledTimerWithTimeInterval:0.6 target:self selector:@selector(showTimeoutActivity:) userInfo:nil repeats:YES]; } else if (globalRowIndex == 1) { _timer = [NSTimer scheduledTimerWithTimeInterval:0.6 target:self selector:@selector(showTimeoutActivity1:) userInfo:nil repeats:YES]; } //[[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes]; //[[NSRunLoop currentRunLoop] run]; [_timer fire]; }); } - (void)showTimeoutActivity:(id)unused { if( [_timer isValid] ) { NSTimeInterval interval = [self.startTime timeIntervalSinceNow]; interval = (-1 * interval); NSString *timerString = [self formatInterval:interval]; NSLog(@"%@", timerString); MyCell *cell = (MyCell *)[self.activeCallTbl viewWithTag:globalRowIndex+10]; //NSIndexPath *indexPath = [self.activeCallTbl indexPathForCell:cell]; //NSLog(@"%d",indexPath.row); cell.timerLbl.text = timerString; } } - (void)showTimeoutActivity1:(id)unused { if( [_timer isValid] ) { NSTimeInterval interval = [self.startTime timeIntervalSinceNow]; interval = (-1 * interval); NSString *timerString = [self formatInterval:interval]; NSLog(@"%@", timerString); MyCell *cell = (MyCell *)[self.activeCallTbl viewWithTag:globalRowIndex+10]; //NSIndexPath *indexPath = [self.activeCallTbl indexPathForCell:cell]; //NSLog(@"%d",indexPath.row); cell.timerLbl.text = timerString; } } 
+4
source share
1 answer

I'm not sure I understand what you are asking for exactly ... but I'm trying.

One simple solution might be to subclass your UITableViewCell and add a timer to the cell itself. Thus, the cell will refer to the timer and will create a new one each time a new cell is added to the TableView

I am attaching a sample code: Link (I added 3 cells statically, but you can add them however you want, just click on one cell to start the timer, if you click again, the timer will start again from 0)

Create your own custom subclass and add the following methods:

 - (void) startTimer { // invalidate a previous timer in case of reuse if (self.timer) [self.timer invalidate]; self.startTime = [NSDate date]; // create a new timer self.timer = [NSTimer scheduledTimerWithTimeInterval:0.6 target:self selector:@selector(calculateTimer) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSRunLoopCommonModes]; [self.timer fire]; } - (void)calculateTimer { NSTimeInterval interval = [self.startTime timeIntervalSinceNow]; interval = (-1 * interval); NSString *intervalString = [NSString stringWithFormat:@"%f", interval]; self.timerLabel.text = intervalString; } 

Then in the implementation of the UITableViewController just call

 - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { TimerCell *cell = [self.tableView cellForRowAtIndexPath:indexPath]; [cell startTimer]; } 

For more information, refer to the attached project or view it.

This is the fastest way I've found, although someone would prefer to leave the timer code and link inside the table view controller (but you need more code)

EDIT

As written in a Spynet comment, this will not work if you have more than 7/8 cells (the number of cells that can fit the screen), because when scrolling, the UITableView cells are reused. Thus, one cell will be used in different indexPath, so starting the timer in the first cell and then scrolling will make you see that the timer is already running every 7/8 cells (since this is a timer of a previously created cell)

There are many ways to solve this. One could remove the timer from the cell and create an array of timers in the ViewController. One timer for each index. Another way (but I have not recomed this if there are a lot of cells) is to not reuse the cells.

Starting from my sample project:
1 - create a nib file (name it TimerCell.xib) and copy / paste the cell prototype inside it from the storyboard
2 - add this property to TimerViewController

 @interface TimerViewController () @property (strong, nonatomic) NSMutableArray *cells; @end 

3 - in the initWithCoder initialize the array:

 - (id)initWithCoder:(NSCoder *)coder { self = [super initWithCoder:coder]; if (self) { _cells = [NSMutableArray array]; } return self; } 

4 - update the cellForRowAtIndexPath method and change it as follows:

 - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { TimerCell *cell = nil; if ([self.cells count] > indexPath.row) { cell = [self.cells objectAtIndex:indexPath.row]; } else { cell = [[[NSBundle mainBundle] loadNibNamed:@"TimerCell" owner:self options:nil] objectAtIndex:0]; [self.cells addObject:cell]; } // Configure the cell... return cell; } 

Thus, the cells will not be reused

+13
source

Source: https://habr.com/ru/post/1486612/


All Articles