Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adjust NSTimer to reduce CPU usage #18

Open
wants to merge 3 commits into
base: master
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 70 additions & 7 deletions UTCMenuClock/UTCMenuClockAppDelegate.m
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ @implementation UTCMenuClockAppDelegate
NSMenuItem *showJulianItem;
NSMenuItem *showTimeZoneItem;

// Hold onto the timer to invalidate it if needed
NSTimer *timer;

/*!
@brief Exits the app
*/
Expand Down Expand Up @@ -101,7 +104,7 @@ - (void) togglePreference:(id)sender {
[sender setState:NSOffState];
[standardUserDefaults setBool:FALSE forKey:preference];
}

[self scheduleTimer];
}

/*!
Expand Down Expand Up @@ -199,7 +202,7 @@ - (NSString *) makeDateString {
BOOL showTimeZone = [self fetchBooleanPreference:showTimeZonePreferenceKey];
BOOL show24HrTime = [self fetchBooleanPreference:show24HourPreferenceKey];
BOOL showISO8601 = [self fetchBooleanPreference:showISO8601PreferenceKey];

// a side effect of this function is that we also update the menu with the proper UTC date.
[UTCdateDF setDateStyle:NSDateFormatterFullStyle];
[UTCdateShortDF setDateStyle:NSDateFormatterShortStyle];
Expand Down Expand Up @@ -259,7 +262,6 @@ - (NSString *) makeDateString {
- (void) doDateUpdate {
NSString *dateString = [self makeDateString];
[ourStatus setTitle:dateString];

}

// Unused for now... need to finish.
Expand All @@ -272,7 +274,7 @@ - (IBAction)showFontMenu:(id)sender {
}

/*!
@brief Fires every one second to update the clock
@brief Fires to update the clock
*/
- (void) fireTimer:(NSTimer*)theTimer {
[self doDateUpdate];
Expand Down Expand Up @@ -496,12 +498,73 @@ - (void)awakeFromNib

[theItem setMenu:(NSMenu *)mainMenu];

// Update the date immediately after our setup so that there is no timer lag
[self scheduleTimer];
}

- (void)scheduleTimer {
// Invalidate and dealloc old timer
[timer invalidate];
timer = nil;

// Update the date immediately
[self doDateUpdate];

// Get the current date components (without ms)
NSDateComponents *startUnits = [[NSCalendar currentCalendar] components:
(NSYearCalendarUnit |
NSMonthCalendarUnit |
NSDayCalendarUnit |
NSCalendarUnitHour |
NSMinuteCalendarUnit |
NSSecondCalendarUnit)
fromDate: [NSDate date]];

NSTimeInterval interval;
NSTimeInterval tolerance;

// Schedule the timer
if ([self fetchBooleanPreference:showSecondsPreferenceKey]) {
// Update every 1 second with 50ms of tolerance to allow for CPU sleep
// (Chosen arbitrarily: 100ms of tolerance makes the updates visibly irregular, 50ms looks fine)

// Start at the next whole second
[startUnits setSecond:[startUnits second] + 1.0];

interval = 1.0;
tolerance = 0.05;
} else {
// If we're not showing seconds, set the timer to fire at the next whole minute then every 60 seconds
[startUnits setSecond:0];
[startUnits setMinute:[startUnits minute] + 1.0];

// Update every 60 seconds with 500ms of tolerance
interval = 60.0;
tolerance = 0.5;
}

// Set up wake notifications to reset the timer after sleep
[self fileNotifications];

NSDate *startDateTime = [[NSCalendar currentCalendar] dateFromComponents:startUnits];
timer = [[NSTimer alloc] initWithFireDate:startDateTime interval:interval target:self selector:@selector(fireTimer:) userInfo:nil repeats:YES];
timer.tolerance = tolerance;

// Schedule the timer
NSNumber *myInt = [NSNumber numberWithInt:1];
[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:@selector(fireTimer:) userInfo:myInt repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
}

- (void)receiveWakeNote: (NSNotification*) note
{
// When the machine wakes from sleep, reset our timer to make sure we're still running on the second/minute
[self scheduleTimer];
}

- (void)fileNotifications
{
// https://developer.apple.com/library/archive/qa/qa1340/_index.html
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver: self
selector: @selector(receiveWakeNote:)
name: NSWorkspaceDidWakeNotification object: NULL];
}

@end