thelontx
thelontx

Reputation: 13

How do I change the displayed time format after NSTimer is initiated?

I'm starting out my iOS experience with a project that incorporates a large clock as a portion of the user interface. When I try to incorporate a user-adjustable toggle to switch from 12-hr to 24-hr time format, I get issues. After the initial user change of the on-screen toggle, the displayed time "flickers" between the 2 formats.

My approach:

  1. viewDidLoad sets the attribute used for 12-hr time format and calls the startTimer method
  2. startTimer method: NSDateFormatter is set. NSTimer is initiated with scheduled interval, passing the DateFormatter to the upDateTime method
  3. updateTimer method checks current time and sets the on-screen
  4. If the user, clicks the on-screen 12-hr/24-hr segmented control, the IBAction invalidates the timer and passes the desired time format attribute to the startTimer method

Testing/Observations:

Root Question: Any suggestions or better approach to having an on-screen clock with a user switch for 12-hr vs. 24-hr time format? Any reason why the displayed time format keeps cycling?

Code:

- (void)startTimer:(NSString *)displayedClockMode {

    // using locale within formatter overrides device system behavior chosen by user
    NSString *localeValue = nil;
    NSDateFormatter *timeFormatter = [[NSDateFormatter alloc] init];
    if([displayedClockMode isEqual:@"12-hr"]){
        //then 12 hr format - based on US locale
        localeValue = @"en_US_POSIX";
        //[timeFormatter setDateFormat:@"hh:mm a"];
    }
    else { //assume no other value exists
        // 24 hr format - based on GB locale
        localeValue = @"en_GB";
        //[timeFormatter setDateFormat:@"HH:mm"];
    }

    NSLocale *clockLocale = [NSLocale localeWithLocaleIdentifier:localeValue];
    [timeFormatter setLocale:clockLocale];
    [timeFormatter setTimeStyle:NSDateFormatterMediumStyle];
    //stop timer before re-starting with new format
    [self.updateTimer invalidate];
    self.updateTimer = nil;

    NSTimer *updateTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateTime:) userInfo:timeFormatter repeats:YES];
}

- (void)updateTime:(NSTimer *)updateTimer {

    NSDate *currentTime = [NSDate date];

    NSLog(@"old display time: %@",self.displayedTime.text);

    self.displayedTime.text = [updateTimer.userInfo stringFromDate:currentTime];

    NSLog(@"new display time: %@",self.displayedTime.text);
    NSLog(@"new timeformatter: %@",updateTimer.userInfo);

}


- (IBAction)displayedTimeMode:(id)sender {

    [self.updateTimer invalidate];
    self.updateTimer = nil;

    NSString *timeFormat = nil;
    if(self.displayedTimeToggle.selectedSegmentIndex == 0){
        //if 0, then 12 hr format
        timeFormat = @"12-hr";
    }
    else {
        // is 1, 24 hr format
        timeFormat = @"24-hr";
    }

    [self startTimer:timeFormat];

}

Upvotes: 1

Views: 198

Answers (1)

Lyndsey Scott
Lyndsey Scott

Reputation: 37300

The problem is that you have two different updateTimers -- self.updateTimer the class variable and updateTimer the local variable. You're invalidating the class variable, but initializing and running multiple local NSTimers with different locales during each call to startTimer. That's why you see this "flickering" -- it's because multiple NSTimers are setting the label using different localeValues.

To fix this, change:

NSTimer *updateTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateTime:) userInfo:timeFormatter repeats:YES];

to

self.updateTimer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(updateTime:) userInfo:timeFormatter repeats:YES];

Upvotes: 2

Related Questions