Reputation: 13
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:
viewDidLoad
sets the attribute used for 12-hr time format and calls the startTimer methodNSDateFormatter
is set. NSTimer
is initiated with scheduled interval, passing the DateFormatter to the upDateTime methodIBAction
invalidates the timer and passes the desired time format attribute to the startTimer methodTesting/Observations:
NSTimer
scheduled interval shows as 1 sec. I have this for testing, but saw same behavior at 0.1 sec.NSLog
calls within the updateTime method show that the DateFormatter object id and the displayed time are changing between successive loops, even though the user did not adjust the toggle switch. [updateTimer invalidate]
to a couple of places in the methods without successRoot 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
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 NSTimer
s 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