Countdown Timer in Cocoa - cocoa

I am wondering if there is some way that I can create a timer that countdown from a given time. For example, say I want this timer to last an hour. There will be a NSTextField that will show the time remaining (ex. 25 minutes), and will auto update every minute to the new value. And then, when an hour is finally passed, it will run some function. I have seen people suggesting NSTimer and NSDate for this, but am wondering what you all could suggest.
Thanks!
EDIT: My current code (timeInstance is an instance variable):
- (void)awakeFromNib:
{
timeInstance = [[NSDate date] addTimeInterval:(10 * 60)];
[timeInstance retain];
[timer invalidate];
timer = [NSTimer scheduledTimerWithTimeInterval:0.1 target:self selector:#selector(timer:) userInfo:NULL repeats:YES];
}
- (void)timer:(NSTimer *)myTimer
{
NSDate *now = [NSDate date];
// Compare
}

NSTimer and NSDate sounds perfectly reasonable.
EDIT: As a side note, it might be a good idea to increase the frequency as the target time approaches; allowing you to change from hour display to minute display to second display.

Related

Xcode time difference in days, hours, minutes and seconds

First of all: I want to say happy new year to everybody reading this!! May 2015 be a great year for all of us :-).
I'm busy with making a function which calculates the time difference between two dates. To be more precise: the time between a time and date given and the current time and date.
So the user selects a date in the past and then the program shows the time difference between the given date and todays date in a timer like so: "hh:mm:ss"
It works okay and updates every second when i select a time of todays date (01-01-2015 10:00:00), but when selecting a date and time in the past (31-12-2014 17:00:00) and compare it to todays date where the time is earlier than yesterday (01-01-2015 14:01:01), it gives me a negative time like a sort of countdown timer: -2:-59:-59.
But i want it to show the opposite of it: 21:01:01 and if possible if it exceeds the 24:00:00, just count on. For example 25:12:39.
This is the code that calculates the difference:
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"dd-MM-YYYY HH:mm:ss"];
NSDate *date1 = [df dateFromString:[NSString stringWithFormat:#"30-12-2014 %#", startedTime]];
NSDate *date2 = [df dateFromString:[NSString stringWithFormat:#"31-12-2014 %#", [self getCurrentTime]]];
NSTimeInterval interval = [date2 timeIntervalSinceDate:date1];
int hours = (int)interval / 3600; // integer division to get the hours part
int minutes = (interval - (hours*3600)) / 60; // interval minus hours part (in seconds) divided by 60 yields minutes
int seconds = (interval - (hours*3600) - (minutes*60)); // interval minus hours part (in seconds) divided by 60 yields minutes
NSString *timeDiff = [NSString stringWithFormat:#"%02d:%02d:%02d", hours, minutes, seconds];
_workingTime.text = [NSString stringWithFormat:#"%#",timeDiff];
Can someone please help?
[df setDateFormat:#"dd-MM-yyyy hh:mm:ss"];
Try after this change of the format string!
And this.. finally.
NSTimeInterval interval = [date2 timeIntervalSinceDate:date1];
if( interval < 0 ) {
interval = [date1 timeIntervalSinceDate:date2];
}
More about date formats here

UIPickerView Changing UIButton Title Size

So I'm making Alarm Clock to test my skills but can't seem to figure this out... What I've got a UIPickerView that gives a user a time that they can select. Once the time is selected the titleLabel on a UIButton is supposed to update with the time they selected and it does, but it shrinks the new time so it's unreadable... Is there something that needs adjusted with the formatting?
Before when my page loads
Here's my code
- (NSDate *)dateFromString:(NSString *)string {
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"HH:mm"];
NSDate *date = [[NSDate alloc] init];
date = [formatter dateFromString:#"15:00"];
assert(date != nil); // Error converting string to date
return date;
}
After when a user has set a time
Any reason why it might be doing this?
You're experiencing middle truncation of the button's text, and there are a couple of cures for this. You can either make the button bigger by simply adjusting its frame. Or, you can adjust the text size of the title label:
[myButton.titleLabel setFont:[UIFont fontWithName:myButton.titleLabel.font.fontName size:10.0f]];
Actually this seemed to resolve the issue.
alarmButton.titleLabel.adjustsFontSizeToFitWidth = YES;

Time comparison in Cocoa

I am storing the date and time in strings using NSUserDefaults when an action is performed. next time the app is run, I want to check the time since the last date and time, and display a message if this is greater than a specified time period.
Is this possible?
In viewDidLoad I retrieve the NSUserDefaults with the saved date and time, and I get the current date, but how do i compare them, and 'do something' if the time difference is bigger than specified?
Use NSDate's timeIntervalSinceDate: method.
By the way, you can store NSDates directly in NSUserDefaults. You don't need to convert them to/from strings.
You could do something like that:
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
NSDate * lastUpdate = [defaults valueForKey:#"mysettingdate"];
if(!lastUpdate){
lastUpdate = [NSDate dateWithTimeIntervalSince1970:0];
}
NSDate *localDate = [NSDate date];
NSTimeInterval timeZoneOffset = [[NSTimeZone defaultTimeZone] secondsFromGMT];
NSTimeInterval gmtTimeInterval = [localDate timeIntervalSinceReferenceDate] + timeZoneOffset;
NSDate *gmtDate = [NSDate dateWithTimeIntervalSinceReferenceDate:gmtTimeInterval];
NSDateComponents *diff = [[NSCalendar currentCalendar] components:NSMinuteCalendarUnit fromDate:lastUpdate toDate:gmtDate options:0];
NSLog(#"diff in minutes:%d", [diff minute]); //or hour, days, seconds
if ([diff minute]>0) {
//do your stuff :)
}

Listening to change to current week?

I'm testing a few things for my self in OS X, and I would like to know what the best way to do this would be.
I have a method, that returns the current week number.
-(NSInteger) getWeekNumber {
NSDate *date = [NSDate date];
NSCalendar *calendar = [NSCalendar currentCalendar];
NSDateComponents *components = [calendar components:NSWeekCalendarUnit fromDate:date];
return [components week];
}
Since this will only happen once a week it seems stupid to have a thread that will refresh my label once every second or so, but I want the label value to change at the exact second the week number change.
I also want to update a label with the current time, that will actually be once a second, or once a minute depending on settings. Should that just be a thread that runs once a second?
There is no need to use threads for simple tasks like these.
NSTimer is the way to go, do something like this for the weekly updates:
// Exact moment the new week starts
NSDate *date =
// Imagine the new week starts in 5 seconds
NSDate *date = [NSDate dateWithTimeIntervalSinceNow:5];
NSTimer *timer = [[NSTimer alloc]
initWithFireDate: date
interval: 60*60*24*7 // Equals one week
target: self
selector: #selector(updateWeekLabel:)
userInfo: nil
repeats: NO
];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
The following function will be triggered when the new week starts:
-(void)updateWeekLabel:(NSTimer*)theTimer
{
// Get current week and update the label.
// Wait for next week or invalidate the timer like this:
[theTimer invalidate];
}
Use something like this for the clock:
NSTimer *timer = [NSTimer
scheduledTimerWithTimeInterval: 1
target: self
selector: #selector(updateTimeLabel:)
userInfo: nil
repeats: YES
];
[[NSRunLoop currentRunLoop] addTimer:timer forMode:NSDefaultRunLoopMode];
Which triggers this function every second:
-(void)updateTimeLabel:(NSTimer*)theTimer
{
// Get current time and update the label.
}

Placing an NSTimer in a separate thread

Note: It's probably worth scrolling down to read my edit.
I'm trying to setup an NSTimer in a separate thread so that it continues to fire when users interact with the UI of my application. This seems to work, but Leaks reports a number of issues - and I believe I've narrowed it down to my timer code.
Currently what's happening is that updateTimer tries to access an NSArrayController (timersController) which is bound to an NSTableView in my applications interface. From there, I grab the first selected row and alter its timeSpent column. Note: the contents of timersController is a collection of managed objects generated via Core Data.
From reading around, I believe what I should be trying to do is execute the updateTimer function on the main thread, rather than in my timers secondary thread.
I'm posting here in the hopes that someone with more experience can tell me if that's the only thing I'm doing wrong. Having read Apple's documentation on Threading, I've found it an overwhelmingly large subject area.
NSThread *timerThread = [[[NSThread alloc] initWithTarget:self selector:#selector(startTimerThread) object:nil] autorelease];
[timerThread start];
-(void)startTimerThread
{
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
NSRunLoop *runLoop = [NSRunLoop currentRunLoop];
activeTimer = [[NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateTimer:) userInfo:nil repeats:YES] retain];
[runLoop run];
[pool release];
}
-(void)updateTimer:(NSTimer *)timer
{
NSArray *selectedTimers = [timersController selectedObjects];
id selectedTimer = [selectedTimers objectAtIndex:0];
NSNumber *currentTimeSpent = [selectedTimer timeSpent];
[selectedTimer setValue:[NSNumber numberWithInt:[currentTimeSpent intValue]+1] forKey:#"timeSpent"];
}
-(void)stopTimer
{
[activeTimer invalidate];
[activeTimer release];
}
UPDATE
I'm still totally lost with regards to this leak. I know I'm obviously doing something wrong, but I've stripped my application down to its bare bones and still can't seem to find it. For simplicities sake, I've uploaded my applications controller code to: a small pastebin. Note that I've now removed the timer thread code and instead opted to run the timer in a separate runloop (as suggested here).
If I set the Leaks Call Tree to hide both Missing Symbols and System Libraries, I'm shown the following output:
EDIT: Links to screenshots broken and therefor removed.
If the only reason you are spawning a new thread is to allow your timer to run while the user is interacting with the UI you can just add it in different runloop modes:
NSTimer *uiTimer = [NSTimer timerWithTimeInterval:(1.0 / 5.0) target:self selector:#selector(uiTimerFired:) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:uiTimer forMode:NSRunLoopCommonModes];
As an addendum to this answer it is now possible to schedule timers using Grand Central Dispatch and blocks:
// Update the UI 5 times per second on the main queue
// Keep a strong reference to _timer in ARC
_timer = dispatch_source_create(DISPATCH_SOURCE_TYPE_TIMER, 0, 0, dispatch_get_main_queue());
dispatch_source_set_timer(_timer, DISPATCH_TIME_NOW, (1.0 / 5.0) * NSEC_PER_SEC, 0.25 * NSEC_PER_SEC);
dispatch_source_set_event_handler(_timer, ^{
// Perform a periodic action
});
// Start the timer
dispatch_resume(_timer);
Later when the timer is no longer needed:
dispatch_source_cancel(_timer);

Resources