Most efficient way of implementing an alarm on iPhone - iphone

I have implemented a simple clock like so:
- (void)runTimer {
timer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(showActivity)
userInfo:nil
repeats:YES];
}
- (void)showActivity {
NSDateFormatter *df = [[[NSDateFormatter alloc] init] autorelease];
NSDate *date = [NSDate date];
[df setDateFormat:#"HH:mm"];
[clock setFont:digitalFont];
[clock setText:[df stringFromDate:date]];
}
It's basiclly just a task that is run every second to update the time in a UILabel. Now what if I would like to extend this clock to react on certain times, just like a alarm clock.
Continously checking the value of NSDate seems battery intensive. How would I do this?

The simplest way to achieve this? Just have another NSTimer that is set to fire at the time of the alarm.
NSTimer* myTimer = [[NSTimer alloc] initWithFireDate:(NSDate *)date
interval:(NSTimeInterval)seconds
target:(id)target
selector:(SEL)aSelector
userInfo:(id)userInfo
repeats:(BOOL)repeats];

You can use initWithFireDate method

Related

Adding one millisecond to current time objectivec

Is there any way to add one millisecond in to current time in objective c . I will fetch the timestamp from server and want to show with millisecond repeatedly ( I dont want to use the system time) .Any help is appreciated .
Thanks in advance .
Read the timestamp into an NSDate. Than use
+ (id)dateWithTimeInterval:(NSTimeInterval)seconds sinceDate:(NSDate *)date
Should work.
You need to use an object of the NSTimer class.
Some sample code:
-(void)startTimer {
theTimer = [NSTimer scheduledTimerWithTimeInterval:1.0/1000.0 target:self selector:#selector(updateTimer) userInfo:nil repeats:YES];
//the method updateTimer will be called once every millisecond
}
-(void)updateTimer {
//add one millisecond to the global time variable and display it in a label
}
-(void)stopTimer {
[theTimer invalidate]; //pauses the timer
}
Edit
For using a global Time variable, NSDate is probably the right class.
You can init the object using a time interval, for eg. 600 seconds before now:
NSDate *globalDateTime = [[NSDate alloc] initWithTimeIntervalSinceNow:-600];
To add 1 millisecond to the time:
globalDateTime = [globalDateTime dateByAddingTimeInterval:1.0/1000.0];
And to populate your global time variable in a string:
NSDateFormatter *dateFormatter = [[NSDateFormatter alloc] init];
[dateFormatter setDateFormat:#"HH:mm:ss"]; // use yyyy-MM-dd if you need to show the year, month or day
NSString *dateTimeString = [dateFormatter stringFromDate:globalDateTime];
The NSTimeInterval class "yields sub-millisecond precision over a range of 10,000 years."
Refer to apple's documentation on NSDate for more details:

Getting the current time and keeping it updated - Objective C

I know how to use NSDate to get the time and display it inside UILabel.
i need to display the date + hours and minutes.
any idea how can i keep it updated without busy-waiting?
Thanks!
Use NSTimer to update time on the label
- (void)viewDidLoad
{
[super viewDidLoad];
[NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(updateTime) userInfo:nil repeats:YES];
}
-(void)updateTime
{
NSDate *date= [NSDate date];
NSDateFormatter *formatter1 = [[NSDateFormatter alloc]init]; //for hour and minute
formatter1.dateFormat = #"hh:mm a";// use any format
clockLabel.text = [formatter1 stringFromDate:date];
[formatter1 release];
}
As your comments said , if you want when minutes changes you change the label.text
you should do like this :
1st: get the current time:
NSDate *date = [NSDate date];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents *dateComponents = [calendar components:NSHourCalendarUnit fromDate:date];
and set the label.text = CURRENTHOUR_AND_YOURMINNUTS;
and then refresh the label next minute,like this :
the first , you can check after 60 - nowSeconds
[self performSelector:#selector(refreshLabel) withObject:nil afterDelay:(60 - dateComponents.minute)];
- (void)refreshLabel
{
//refresh the label.text on the main thread
dispatch_async(dispatch_get_main_queue(),^{ label.text = CURRENT_HOUR_AND_MINUTES; });
// check every 60s
[self performSelector:#selector(refreshLabel) withObject:nil afterDelay:60];
}
It will check every minute , so the effecent is more than answers above.
When refreshLabel invocated , it means the minutes changed
You can use the NSTimer to periodically get the current time.
[NSTimer scheduledTimerWithTimeInterval:2 target:self selector:#selector(timerFired:) userInfo:nil repeats:YES];
- (void)timerFired:(NSTimer*)theTimer{
//you can update the UILabel here.
}
You can use NSTimer , but , given the above methods , the UILabel won't update on touch Events as the main thread will be busy tracking it.You need to add it to mainRunLOOP
NSTimer* timer = [NSTimer timerWithTimeInterval:1.0f target:self selector:#selector(updateLabelWithDate) userInfo:nil repeats:YES];
[[NSRunLoop mainRunLoop] addTimer:timer forMode:NSRunLoopCommonModes];
-(void)updateLabelWithDate
{
//Update your Label
}
You can change the time interval(rate at which you want Updation).

Objective-C Perform method at given time daily - messy implementation

I have the following (terible) method that constantly checks the current time, and when a certain time is reached (in this case midnight) an NSLog statement is run once to signify something useful being done:
- (void) checkTime {
while (true){
NSAutoreleasePool *loopPool = [[NSAutoreleasePool alloc] init];
NSDate *now = [[NSDate alloc] init];
NSDateFormatter *outputFormatter = [[NSDateFormatter alloc] init];
[outputFormatter setDateFormat:#"HH:mm"];
NSString *nowDateString = [outputFormatter stringFromDate:now];
if([nowDateString isEqualToString:#"00:00"]){
NSLog(#"Store previous days data..");
BOOL stillMidnight = YES;
while(stillMidnight == YES){
NSDate *latestNow = [[NSDate alloc] init];
NSDateFormatter *latestOutputFormatter = [[NSDateFormatter alloc] init];
[latestOutputFormatter setDateFormat:#"HH:mm"];
NSString *latestString = [latestOutputFormatter stringFromDate:latestNow];
//Check if it is still midnight
if([latestString isEqualToString:#"00:01"]){
//leave while
stillMidnight = NO;
}
}
NSLog(#"No longer midnight");
}
[loopPool drain];
}
}
The above method gets called as follows from the applicationDidFinishLaunchingWithOption method:
[self performSelectorInBackground:#selector(checkTime) withObject:nil];
This code runs the NSLog(#"Store previous days data..") once at midnight, which is what I need, but is there a more elegant solution to this problem?
Thanks,
Jack
You'd be better off:
getting the current date;
working out when midnight was today;
scheduling a one-shot timer to occur one day after that; and
repeating
It's tempting to just schedule a repeating timer that first fires with the date calculated at (3) and every 24 hours hence, but that would fail to allow for daylight savings. So, e.g. (coded directly in here, untested)
- (void)scheduleNextTimedAction
{
// get the date now and the calendar the user is using
// (which will include their time zone, helpfully)
NSDate *dateNow = [NSDate date];
NSCalendar *relevantCalendar = [NSCalendar currentCalendar];
// decompose the current date to components; we'll
// just ask for month, day and year here for brevity;
// check out the other calendar units to decide whether
// that's something you consider acceptable
NSDateComponents *componentsForNow =
[relevantCalendar components:
NSYearCalendarUnit|NSMonthCalendarUnit|NSDayCalendarUnit
fromDate:dateNow];
// we could explicitly set the time to midnight now,
// but since that's 00:00 it'll already be the value
// in the date components per the standard Cocoa object
// creation components, so...
// get the midnight that last occurred
NSDate *lastMidnight = [relevantCalendar dateFromComponents:componentsForNow];
// can we just add 24 hours to that? No, because of DST. So...
// create components that specify '1 day', however long that may be
NSDateComponents *oneDay = [[NSDateComponents alloc] init];
oneDay.day = 1;
// hence ask the calendar what the next midnight will be
NSDate *nextMidnight = [relevantCalendar
dateByAddingComponents:oneDay
toDate:lastMidnight
options:0];
[oneDay release];
// now create a timer to fire at the next midnight, to call
// our periodic function. NB: there's no convenience factory
// method that takes an NSDate, so we'll have to alloc/init
NSTimer *timer = [[NSTimer alloc]
initWithFireDate:nextMidnight
interval:0.0 // we're not going to repeat, so...
target:self
selector:#selector(doTimedAction:)
userInfo:nil
repeats:NO];
// schedule the timer on the current run loop
[[NSRunLoop currentRunLoop]
addTimer:timer
forMode: NSDefaultRunLoopMode];
// timer is retained by the run loop, so we can forget about it
[timer release];
}
- (void)doTimedAction:(NSTimer *)timer
{
NSLog(#"do action");
[self scheduleNextTimedAction];
}
If you want to execute code at an arbitrary point in time, you best set up Local Notifications.
You can use either an UILocalNotification if the timer should also alert the user when your app is not running Push notification guide or NSTimer, which can be initialized with firing date or interval as well as selector to be called. Note that NSTimer will not fire if your app is in the background but in this case rather will fire the moment your app gets active again.

Local time on the iPhone

I need to display the exact local time and the time should be running.
Please help, if possible with sample code or explanation.
Thanks.
This returns the current date with Time
[NSDate date];
Now you can use NStimer to fetch the time every one second and display it.
NSTimer *timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:#selector(displayTime) userInfo:nil repeats:NO];
//Time Interval is one second
-(void) displayTime
{
NSDate *currentDate = [NSDate date];
NSDateFormatter *timeFormatter = [[[NSDateFormatter alloc]init]autorelease];
timeFormatter.dateFormat = #"HH:mm:ss a";
NSString *dateString = [timeFormatter stringFromDate: currentDate];
yourlabel.text = dateString;
[timeFormatter release]
}

Consistent 1-Second-Long lag at 0:02 during NSTimer in "stopwatch-like" app

I have an app that uses a stopwatch-style count up from 0 in HH:mm:ss format. The code looks pretty straightforward to me, and I can't think of a more efficient way to run it.
For some reason, when I run it, there is a very noticeable and consistent (every time I run it, in the same place) lag when the timer gets to 00:00:02. It stays on 00:00:02 for a full second, and then counts on normally. Why would this happen?
-(IBAction)startAndStop;
{
if (!timer) {
NSLog(#"Pressing Start Button");
[startAndStopButton setTitle:#"Stop" forState:0];
startDate = [[NSDate date] retain];
timerLabel.text = #"00:00:00";
timer = [NSTimer scheduledTimerWithTimeInterval:1
target:self
selector:#selector(timerStart)
userInfo:nil
repeats:YES];
} else {
NSLog(#"Pressing Stop Button");
[startAndStopButton setTitle:#"Start" forState:0];
[startDate release];
[timer invalidate];
timer = nil;
[timer release];
}
}
-(void)timerStart
{
NSDate *currentDate = [NSDate date];
NSTimeInterval countInSeconds = [currentDate timeIntervalSinceDate:startDate];
NSDate *timerDate = [NSDate dateWithTimeIntervalSinceReferenceDate:countInSeconds];
NSDateFormatter *df = [[NSDateFormatter alloc] init];
[df setDateFormat:#"HH:mm:ss"];
[df setTimeZone:[NSTimeZone timeZoneForSecondsFromGMT:0.0]];
NSString *timeString = [df stringFromDate:timerDate];
[df release];
timerLabel.text = timeString;
}
NSTimer does not fire at exact times or time intervals (check the specification for the likely error). Thus it is possible for one late firing and one early firing to occur during the same clock second, when rounded to the nearest second, and you will see a stutter effect.
Instead, use a much faster timer (or CADisplaylink), say at 30 Hz, check the time, and update the label only if the time has changed enough to change the label (one second).
The interval you are passing is in seconds:
http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSTimer_Class/Reference/NSTimer.html
My guess is that it is getting called immediately, and then every 1 second afterwards, since you are passing 1 second as the timer interval. Try passing something like 1.0/20.0 to update at a higher frame rate.