Reputation: 680
I'm working on creating a timer, which is in the format of HH:mm, but my issue right now is pausing the timer and resuming it. Right now, when you pause the timer, it continues to count in the background, but the visible portion has stopped. Once you click on the resume button, the timer updates to where it left off, which, pending how long you it had been paused, could be any number above what it should be.
For instance, if the timer counted to 5, you then pause the timer, which now is sitting at 5, once you click resume, the timer may start at 15 since it had been 10 seconds since you paused it. Below is my code, which I have combined from several places to get this working:
- (void) createTimerPage
{
_dateFormat = [NSDate date];
// Add pause button
UIImage *pause = [UIImage imageNamed:@"pause.png"];
_pauseBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_pauseBtn.frame = CGRectMake(151, 17, 32, 32);
[_pauseBtn addTarget:self action:@selector(pauseTimer) forControlEvents:UIControlEventTouchUpInside];
[_pauseBtn setBackgroundImage:pause forState:UIControlStateNormal];
}
- (void) startTimer
{
// Start timer
NSInteger secondsSinceStart = (NSInteger) [[NSDate date] timeIntervalSinceDate:_dateFormat];
NSInteger seconds = secondsSinceStart % 60;
NSInteger minutes = (secondsSinceStart / 60) % 60;
NSString *result = nil;
result = [NSString stringWithFormat:@"%02d:%02d", minutes, seconds];
_timerText.text = result;
[_timerBtns addSubview:_pauseBtn];
}
- (void) startPressed
{
[_time invalidate];
_time = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(startTimer)
userInfo:nil
repeats:YES];
}
- (void) pauseTimer
{
if (_time) {
// pause timer
[_time invalidate];
[_timerBtns addSubview:_playBtn];
}
}
Upvotes: 0
Views: 155
Reputation: 680
I was actually able to figure this one out with some more research on the matter. I found a great example that helped me come up with the following:
- (IBAction)startRepeatingTimer:(id)sender
{
// Show feed text while timer is going
_feeding = [[UILabel alloc] initWithFrame:CGRectMake(92, 25, 100, 50)];
_feeding.text = @"FEEDING";
_feeding.textColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:1];
if (_feeding) {
_feeding.hidden = NO;
}
[_timerArea addSubview:_feeding];
// Cancel preexisting timer
[_repeatingTimer invalidate];
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(timerTicked:)
userInfo:nil repeats:YES];
_repeatingTimer = timer;
if (_playBtn.hidden == NO) {
_playBtn.hidden = YES;
_pauseBtn.hidden = NO;
}
if (_bWindow.frame.origin.y == 0) {
[UIView animateWithDuration:0.3
animations:^ {
_bWindow.frame = CGRectMake(0, 0, self.view.frame.size.width, 203);
_bWindow.frame = CGRectMake(0, -130, self.view.frame.size.width, 203);
}];
}
[_timerBtns addSubview:_pauseBtn];
}
- (void) timerTicked:(NSTimer *)timer
{
_currentTimeInSeconds++;
_timerText.text = [self targetMethod:_currentTimeInSeconds];
}
- (IBAction)resetTimer:(id)sender
{
_feeding.hidden = YES;
if (_repeatingTimer) {
[_repeatingTimer invalidate];
}
if (_playBtn.hidden == YES) {
_playBtn.hidden = NO;
_pauseBtn.hidden = YES;
}
_currentTimeInSeconds = 0;
_timerText.text = [self targetMethod:_currentTimeInSeconds];
if (_bothBtn.hidden == YES) {
_bothBtn.hidden = NO;
_switchBView.hidden = YES;
}
if (_rightBtn.hidden == YES) {
_rightBtn.hidden = NO;
_switchRView.hidden = YES;
}
if (_leftBtn.hidden == YES) {
_leftBtn.hidden = NO;
_switchLView.hidden = YES;
}
}
- (IBAction)pauseRepeatingTimer:(id)sender
{
[_repeatingTimer invalidate];
if (_playBtn.hidden == YES) {
_playBtn.hidden = NO;
_pauseBtn.hidden = YES;
}
}
- (NSString *) targetMethod:(int)totalSeconds
{
//NSInteger secondsSinceStart = (NSInteger) [[NSDate date] timeIntervalSinceDate:_dateFormat];
int seconds = totalSeconds % 60;
int minutes = (totalSeconds / 60) % 60;
return [NSString stringWithFormat:@"%02d:%02d", minutes, seconds];
}
Upvotes: 0
Reputation: 890
I suspect the problem is that you are storing the "start time" in the variable called "_dateFormat". That variable only gets set when createTimerPage is called so, of course, when you later attempt to determine the secondsSinceStart in startTimer, it is still computing the time since createTimerPage was called.
Honestly, for what you are trying to do, I would not worry about a start time at all. Instead, I would just use a counter of the number of times the timer method gets called. I would also rename some of your methods to make it clearer what is actually going on. For example, your "startTimer" method isn't actually starting a timer. It's what gets called when your one second timer fires.
Finally, one other issue is that you are constantly adding subviews but, at least with the code posted, never removing them. You could (should) remove the unused subview every time you add a new one. Honestly, though, you would be better off leaving both views as part of your view hierarchy and using the hidden attribute to only show one of them.
Something like this will do what you want:
NSUInteger _timerSeconds;
NSTimer * _timer;
- (void) createTimerPage
{
// Add pause button
UIImage *pause = [UIImage imageNamed:@"pause.png"];
_pauseBtn = [UIButton buttonWithType:UIButtonTypeCustom];
_pauseBtn.frame = CGRectMake(151, 17, 32, 32);
[_pauseBtn addTarget:self action:@selector(pausePressed) forControlEvents:UIControlEventTouchUpInside];
[_pauseBtn setBackgroundImage:pause forState:UIControlStateNormal];
[_timerBtns addSubview:_pauseBtn];
}
- (void) timerFired
{
_timerSeconds++;
NSInteger seconds = _timerSeconds % 60;
NSInteger minutes = (_timerSeconds / 60) % 60;
NSString * result = [NSString stringWithFormat:@"%02d:%02d", minutes, seconds];
_timerText.text = result;
}
- (void) startPressed
{
// start timer
_timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:@selector(timerFired)
userInfo:nil
repeats:YES];
_playBtn.hidden = YES;
_pauseBtn.hidden = NO;
}
- (void) pausePressed
{
if (_timer) {
// pause timer
[_timer invalidate];
_playBtn.hidden = NO;
_pauseBtn.hidden = YES;
}
}
Upvotes: 1