Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
415 views
in Technique[技术] by (71.8m points)

ios - Using timer in a tableview re creates the timer after any scroll or table reload

I'm using https://github.com/mineschan/MZTimerLabel/ and in my Tableview cellForRowAtIndex using the timer like below:

UILabel *lblTimer=(UILabel *)[cell viewWithTag:10];
MZTimerLabel *UpgradeTimer = [[MZTimerLabel alloc] initWithLabel:lblTimer andTimerType:MZTimerLabelTypeTimer];
[UpgradeTimer setCountDownTime:timestamp];
[UpgradeTimer startWithEndingBlock:^(NSTimeInterval timestamp) {
lblTimer.text = @"?";
}];

But after any table reloading or scrolling, the timer behaves strange and seems it re-generates multiple timers for counting in the same place. How should I fix this while using this timer?

Appreciate any help,

Elias

See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

I had a look at MZTimerLabel, and it violates MVC badly. It puts something that belongs into the model (the timer that count's down the time) into the view. That is where your problem comes from. Views should be able to be recreated without having side effects on the model.

I would recommend to ditch that class, and create your own. It's actually quite easy to achieve something like this.

  1. Create a new class that saves a title and a endDate
  2. Store instances of that class in the model that backs your table
  3. Create one NSTimer that refreshes the tableView
  4. Set up your cells.

That's basically all the code you need for a basic countdown in a table. Because it does not store any data in the view you can scroll as much as you like:

@interface Timer : NSObject
@property (strong, nonatomic) NSDate *endDate;
@property (strong, nonatomic) NSString *title;
@end

@implementation Timer
@end

@interface MasterViewController () {
    NSArray *_objects;
    NSTimer *_refreshTimer;
}
@end

@implementation MasterViewController

- (void)viewDidLoad
{
    [super viewDidLoad];

    NSMutableArray *modelStore = [NSMutableArray arrayWithCapacity:30];
    for (NSInteger i = 0; i < 30; i++) {
        Timer *timer = [[Timer alloc] init];
        timer.endDate = [NSDate dateWithTimeIntervalSinceNow:i*30];
        timer.title = [NSString stringWithFormat:@"Timer %ld seconds", (long)i*30];
        [modelStore addObject:timer];
    }
    _objects = modelStore;
}

- (void)viewWillAppear:(BOOL)animated {
    [super viewWillAppear:animated];
    [_refreshTimer invalidate]; // timer should not exist, but just in case.
    _refreshTimer = [NSTimer timerWithTimeInterval:0.5f target:self selector:@selector(refreshView:) userInfo:nil repeats:YES];

    // should fire while scrolling, so we need to add the timer manually:
    [[NSRunLoop currentRunLoop] addTimer:_refreshTimer forMode:NSRunLoopCommonModes];
}

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    [_refreshTimer invalidate];
    _refreshTimer = nil;
}

- (void)refreshView:(NSTimer *)timer {
    // only refresh visible cells
    for (UITableViewCell *cell in [self.tableView visibleCells]) {
        NSIndexPath *indexPath = [self.tableView indexPathForCell:cell];
        [self configureCell:cell forRowAtIndexPath:indexPath];
    }
}

#pragma mark - Table View

- (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section
{
    return _objects.count;
}

- (void)configureCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    Timer *timer = _objects[indexPath.row];
    cell.textLabel.text = timer.title;
    NSInteger timeUntilEnd = (NSInteger)[timer.endDate timeIntervalSinceDate:[NSDate date]];
    if (timeUntilEnd <= 0) {
        cell.detailTextLabel.text = @"Finished";
    }
    else {
        NSInteger seconds = timeUntilEnd % 60;
        NSInteger minutes = (timeUntilEnd / 60) % 60;
        NSInteger hours = (timeUntilEnd / 3600);
        cell.detailTextLabel.text = [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)hours, (long)minutes, (long)seconds];
    }
}

- (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath {
    UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:@"Cell" forIndexPath:indexPath];
    [self configureCell:cell forRowAtIndexPath:indexPath];
    return cell;
}

@end

enter image description here


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...