How to update label once a day? - ios

I'd like to have a label in my app that gets updated once a day at a specific time (i.e. 12 a.m.). If you could help me out I'd really appreciate it, thanks.
This is what i currently have but it only works if the app is opened between 12 and 1 am.
NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
[formatter setDateFormat:#"HH"];
NSString *stringDate = [formatter stringFromDate:[NSDate date]];
if ([stringDate isEqualToString:#"00"]) {
NSLog(#"its working");
[self changeLabel];
}
To clarify, I'm trying to change the text of a label once a day. I'd like to have the label update at a specific time like 12 am so that it updates with the start of each new day. I've tried a few ways of doing this but haven't gotten the desired result. If anyone knows of a way to do this I'd appreciate your input.

If you only need to determine the last time the application was opened, you can use NSUserDefaults to save the date and then check that the approprate number of seconds (86400 = 1 day) have passed.
Something along the lines of the following should point you in the right direction:
//gather last time app was opened
NSDate *lastUpdated = [[NSUserDefaults standardUserDefaults] objectForKey:#"app_last_updated"];
//check date is valid
if(lastUpdated)
{
//determine number of seconds that have passed
NSTimeInterval timeInterval = [lastUpdated timeIntervalSinceNow];
//check time interval is greater than 1 day
if(timeInterval > 86400)
{
//update label
}
}
//save current time
[[NSUserDefaults standardUserDefaults] setObject:[NSDate date] forKey:#"app_last_updated"];

It depends on what you want to do. On iOS, most likely your app is not running in the foreground all the time. So I would just update the label when the application is active in applicationDidBecomeActive:. Then I would create a timer to fire at the specific date/time I want.
For example:
NSDate *d = // create the next date/time
updateTimer_ = [[NSTimer alloc] initWithFireDate: d
interval: 0
target: self
selector:#selector(updateLabel:)
userInfo:nil repeats:NO];
NSRunLoop *runner = [NSRunLoop currentRunLoop];
[runner addTimer:updateTimer_ forMode: NSDefaultRunLoopMode];

I know this is an old post but a few days ago I needed just what Dave123 asked and I came up with this solution after searching a lot on the web:
- (void)applicationDidBecomeActive:(UIApplication *)application {
NSLog(#"applicationDidBecomeActive");
self.masterviewController = [[PBMasterViewController alloc] init];
// Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
NSLog(#"Seconds --------> %.f",[[NSDate date] timeIntervalSinceDate:[[NSUserDefaults standardUserDefaults] objectForKey:#"OLD_DATE"]]);
NSLog(#"old date: %#", [[NSUserDefaults standardUserDefaults] objectForKey:#"OLD_DATE"]);
// 24 hours must elapse between each update check
if ([[NSDate date] timeIntervalSinceDate:[[NSUserDefaults standardUserDefaults] objectForKey:#"OLD_DATE"]] > 86400) {
NSLog(#"Time elapsed since last update is MORE than 1 day. Check for updates.");
[self.masterviewController checkForUpdates];
} else {
NSLog(#"Time elapsed since last update is LESS than 1 day. Don't check for updates.");
}
// Here I convert the seconds into hours with two decimals, if you want to show the time elapsed in a UILabel
NSString *stringCheckInterval = [NSString stringWithFormat:#"%.02f hours since last update", [[NSDate date] timeIntervalSinceDate:[[NSUserDefaults standardUserDefaults] objectForKey:#"OLD_DATE"]] / 60 / 60];
NSLog(#"%#", stringCheckInterval);
}

is there someone that has the app opened form more than 24h??
Anyway, you can simply use an NSTimer with 86400 as delay time.

When you start the app, set up a timer that will fire at 12:00:01 AM and update your label.

Related

NSTimeInterval not always firing

I'm working on a simple radio alarm clock app for a non-mainstream stream I'd like to wake up to. It uses the opting out of background trick to stay running when the phone is locked, similar to Rise/Sleepcycle.
Originally the alarm wouldn't fire the next day if I was to set the alarm before midnight but would always fire pretty much on the turn of the minute if set ahead of the current time but before 00:00
So I've made some adjustments so that the date is also checked. I also included conditions so that it's impossible to set a time before the current time. Now while this takes care of the next day issue, I'm finding the fire itself is temperamental. Sometimes it works perfectly, sometimes there is a huge delay (up to 10 minutes in cases) sometimes it never fires at all. I really cannot figure out for the life of me why this happens.
Below is my code. Does anyone have any ideas as to why it's not consistent?
- (void)viewDidLoad {
[super viewDidLoad];
radio = [[Radio alloc] initWithUserAgent:#"my app"];
[radio connect:STREAM_URL withDelegate:self withGain:(1.0)];
// dateTimePicker.date = [NSDate date];
dateTimePicker.date =
[[ NSDate alloc ] initWithTimeIntervalSinceNow: (NSTimeInterval) 2];
dateTimePicker.minimumDate =
[[ NSDate alloc ] initWithTimeIntervalSinceNow: (NSTimeInterval) 0 ];
}
-(void) presentMessage:(NSString *)message {
UIAlertView *alert = [[UIAlertView alloc] initWithTitle:#"Radio Alarm" message: message delegate:nil cancelButtonTitle:#"Ok" otherButtonTitles: nil];
[alert show];
}
- (IBAction)alarmSetButtonTapped:(id)sender {
NSLog( #"Alarm Set Button Tapped");
NSDateFormatter * dateFormatter = [[NSDateFormatter alloc] init];
dateFormatter.timeZone = [NSTimeZone defaultTimeZone];
dateFormatter.timeStyle = NSDateFormatterShortStyle;
dateFormatter.dateStyle = NSDateFormatterShortStyle;
NSString * dateTimeString = [dateFormatter stringFromDate: dateTimePicker.date];
NSLog( #"Alarm Set Button Tapped : %#", dateTimeString);
[self presentMessage:[NSString stringWithFormat:#"Alarm set for %#", dateTimeString]];
NSDate *alarmFireDate = dateTimePicker.date;
NSTimeInterval differenceFromNow = [alarmFireDate timeIntervalSinceNow];
//[alarmFireDate performSelector:#selector(PlayAlarm:) withObject:nil afterDelay:differenceFromNow];
[self performSelector:#selector(PlayAlarm:)
withObject:(self)
afterDelay:(differenceFromNow)];
you can use
[NSTimer scheduledTimerWithTimeInterval:differenceFromNow
target:self
selector:#selector(PlayAlarm:)
userInfo:nil
repeats:NO];
This timer is quite accurate.
If you need to abort the timer, just save the returned NSTimer* from this in a property and call
[myTimer invalidate];

ios How to fetch App launch time?

Now I need to get the user opening the APP's time,and compare the time to the last time, if the time is more than 24 hours, just to remind the user of updating App. Who knows the Objective-C code about this? Please help me .Thank U very much!
Create a NSDate member variable (i.e NSDate *startDate) in your AppDelegate file. Now in AppDelegate.m class use the below code.
- (void)applicationDidEnterBackground:(UIApplication *)application {
// save the last app opening time, you can save in NSuserdefaults also
startDate = [NSDate date];
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
NSDate *now = [NSDate date];
// Returns in seconds
NSTimeInterval timeInterval = [now timeIntervalSinceDate:startDate]
if(timeInterval > (24*3600)) {
// remind the user of updating App here.
}
}
I will suggest to store the values in user defaults , so that if user exits the app even then we can have the data time details. Add the below code in app delegate - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
NSDate *dateTimenow=[NSDate date];
NSDateFormatter *dateFormatter=[[NSDateFormatter alloc]init];
[dateFormatter setDateFormat:#"dd-MM-yyyy hh:mm"];
NSString *strDateTimeNow=[NSString stringWithFormat:#"%#",[dateFormatter stringFromDate:dateTimenow]];
NSLog(#"now date time: %#",strDateTimeNow);
NSUserDefaults *userdefaults=[NSUserDefaults standardUserDefaults];
if ([userdefaults valueForKey:#"LastAppLaunchTime"]) {
NSString *strPreviousDateTime=[NSString stringWithFormat:#"%#",[userdefaults valueForKey:#"LastAppLaunchTime"]];
NSLog(#"previous date time: %#",strPreviousDateTime);
//Now you can compare current date time with previous date time
//perform task after comparing
}
[userdefaults setValue:strDateTimeNow forKey:#"LastAppLaunchTime"];// saving recent date time details for next time
you can also do this while going in background and coming to foreground, so if app is suspended in background for more than 24 hours then also you can perform your task. I hope this helps.
You can use NSDate:
NSDate* now = [NSDate date];
Save this value as lastTimeOpened and compare during next launch:
if ([now timeIntervalSinceDate:lastTimeOpened] > someTime)

Timer in Today Extension Freezes Extension

I have a timer to a date counting down in my today widget. I am gathering the date from my View Controller and then starting a timer in the extension and from there I am displaying the dates in three labels, Hours, Minutes, and Seconds. In my app... this is perfect, but not so true in the notification center. The countdown loads correctly and works great for about 20 seconds. After that it skips a second and freezes, then it starts again in about 4 seconds and then it will reset the whole widget (everything disappears) and then about 2 seconds later the whole widget resets. Is this a memory warning or something?
View Controller:
mainTextLabel.text = 436496400
NSUserDefaults *sharedDefaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.nicmac.nextgame"];
[sharedDefaults setObject:mainTextLabel.text forKey:#"MyNumberKey"];
[sharedDefaults synchronize];
Today View Controller
- (id)initWithCoder:(NSCoder *)aDecoder {
if (self = [super initWithCoder:aDecoder]) {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:#selector(userDefaultsDidChange:)
name:NSUserDefaultsDidChangeNotification
object:nil];
}
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
self.preferredContentSize = CGSizeMake(320, 300);
[self performSelector:#selector(updateNumberLabelText) withObject:nil afterDelay:1.0];
}
- (void)userDefaultsDidChange:(NSNotification *)notification {
[self performSelector:#selector(updateNumberLabelText) withObject:nil afterDelay:1.0];
}
- (void)updateNumberLabelText {
NSUserDefaults *defaults = [[NSUserDefaults alloc] initWithSuiteName:#"group.nicmac.nextgame"];
NSString *date = [defaults stringForKey:#"MyNumberKey"];
self.numberLabel.text = [NSString stringWithFormat:#"%#", date];
NSString *doubleString = self.numberLabel.text;
double value = [doubleString doubleValue];
destinationDate = [NSDate dateWithTimeIntervalSince1970:value];
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateNumberLabelText) userInfo:nil repeats:YES];
NSCalendar *calendar = [[NSCalendar alloc] initWithCalendarIdentifier:NSCalendarIdentifierGregorian];
int units = NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond;
NSDateComponents *components = [calendar components:units fromDate:[NSDate date] toDate:destinationDate options:0];
[hour setText:[NSString stringWithFormat:#"%ld", (long)[components day] * 24 + (long)[components hour]]];
[minute setText:[NSString stringWithFormat:#"%ld", (long)[components minute]]];
[second setText:[NSString stringWithFormat:#"%ld", (long)[components second]]];
}
Thanks!
The problem here lies in the - (void)updateNumberLabelText method.
Specifically, here:
timer = [NSTimer scheduledTimerWithTimeInterval:1.0 target:self selector:#selector(updateNumberLabelText) userInfo:nil repeats:YES];
This means that every time you're calling this method, it's scheduling another timer to call this method every second (every second because repeats:YES). That means, every second (with a micro offset because of any lag in the computer), x number of scheduled timers is producing x MORE number of scheduled timers, meaning that every second you have double the number of timers. This is called exponential growth, and can be modelled to 2^x.
So to find the number of timers in 20 seconds:
2^1+2^2+2^3+2^4+2^5+2^6+2^7+2^8+2^9+2^10+2^11+2^12+2^13+2^14+2^15+2^16+2^17+2^18+2^19+2^20
Ew, can we represent this better - we can! We can use sigma notation like so:
<no. of seconds>
Σ 2^i
i=1
But enough math. That averages out to around a whopping 2,000,000 timers initialised in 20 seconds. That is a lot of timers, and the widget eventually struggles to catch breath (no more memory!) and dies/crashes/restarts itself.
Here's how to fix it:
If you really want this method to loop itself, call
[self performSelector:#selector(updateNumberLabelText) withObject:nil afterDelay:1.0];
in the method instead.
You could do it the way you're currently doing it and do repeats:NO instead, but I don't think that the timer will invalidate itself after the 1.0 second, and creating that many timers is not very efficient.

Get the length of time the iPhone was locked

How would I get the length of time a phone was locked if I wanted to use it to increment a timer progress view when the phone was resumed, or schedule a notification to fire when the phone was still locked?
Implement the UIApplicationDelegate method applicationWillResignActive: and applicationDidBecomeActive:.
You will have to store the current time when the former is called and calculate the difference when the latter is called. Specifically, in your application delegate:
#define TIMESTAMP_KEY #"timestamp"
- (void)applicationWillResignActive:(UIApplication *)application
{
NSInteger *timestamp = [[NSDate date] timeIntervalSince1970];
[[NSUserDefault standardUserDefaults] setInteger:timestamp forKey:TIMESTAMP_KEY];
}
- (void)applicationDidBecomeActive:(UIApplication *)application
{
NSInteger *newTimestamp = [[NSDate date] timeIntervalSince1970];
NSInteger *oldTimestamp = [[NSUserDefault standardUserDefaults] integerForKey:TIMESTAMP_KEY];
NSInteger *secondsPassed = newTimestamp - oldTimestamp;
// Now you can resynch your timer with the secondsPassed
}

NSTimer with NSUserDefaults

How do I have an NSTimer with a UIButton that changes its text from Start to Stop, Also another UIButton will be added to pause the timer. So, You press start and then the timer will show in a label in hours, minutes and seconds. While the timer is running, is there a way to pause the timer ( I heard you have to use NSUserDefaults). Also is there a way to save the time at which the start button was pressed and then to save the time that the button was pressed again to stop? Also when the pause button is pressed to pause the timer and when pause is pressed again it will resume the timer?
If you need a timer that doesn't support pausing, you only need to know the NSDate at which the timer started so that you can calculate the time elapsed. Create an instance variable:
#property (strong, nonatomic) NSDate *timerStartDate;
When the button is tapped:
- (void)startTimer
{
self.timerStartDate = [NSDate date];
}
Your NSTimer is not to keep track of the time, but to periodically update the label. Create an instance variable:
#property (strong, nonatomic) NSTimer *labelUpdateTimer;
and update the -startTimer method:
- (void)startTimer
{
self.timerStartDate = [NSDate date];
// start timer to update label
if (!self.labelUpdateTimer) {
self.labelUpdateTimer = [NSTimer scheduledTimerWithTimeInterval:1.0
target:self
selector:#selector(updateLabel)
userInfo:nil
repeats:YES];
}
}
- (void)updateLabel
{
NSTimeInterval secondsElapsedSinceTimerStart = 0;
if (self.timerStartDate) {
secondsElapsedSinceTimerStart = [[NSDate date] timeIntervalSinceDate:self.timerStartDate];
}
NSString *formattedTime = <format time elapsed the way you like>;
self.label.text = formattedTime;
}
- (void)dealloc
{
// make sure timer is not firing anymore!
if (_labelUpdateTimer) {
[_labelUpdateTimer invalidate];
_labelUpdateTimer = nil;
}
}
However, if you want to be able to pause the timer, besides calculating the time elapsed since the timer last started, you'll need to store the time previously elapsed (if you started/paused the timer before). Create an instance variable:
#property (nonatomic) NSTimeInterval previouslyElapsedSeconds;
And when you pause the timer:
- (void)pauseTimer
{
// update elapsedSeconds
if (self.timerStartDate) {
self.previouslyElapsedSeconds += [[NSDate date] timeIntervalSinceDate:self.timerStartDate];
self.timerStartDate = nil;
}
[self.labelUpdateTimer invalidate];
self.labelUpdateTimer = nil;
}
Update -updateLabel:
- (void)updateLabel
{
NSTimeInterval secondsElapsedSinceTimerStart = 0;
if (self.timerStartDate) {
secondsElapsedSinceTimerStart = [[NSDate date] timeIntervalSinceDate:self.timerStartDate];
}
// account for previously elapsed time
NSTimeInterval totalSecondsElapsed = self.previouslyElapsedSeconds + secondsElapsedSinceTimerStart;
NSString *formattedTime = <format time elapsed the way you like>;
self.label.text = formattedTime;
}
NSUserDefaults will be required only if you want to keep timing even if the app is shut down (not just backgrounded). In that case store previouslyElapsedSeconds and timerStartDate in NSUserDefaults instead of as instance variables.
assuming you have NSDate objects startTime and stopTime
[[NSUserDefaults standardUserDefaults] setObject:startTime forKey:#"startTime"];
[[NSUserDefaults standardUserDefaults] setObject:stopTime forKey:#"stopTime"];
Or you can use floats startTimef and stopTimef
[[NSUserDefaults standardUserDefaults] setFloat:startTimef forKey:#"startTime"];
[[NSUserDefaults standardUserDefaults] setFloat:stopTimef forKey:#"stopTime"];
Check out the NSUserDefaults docs.
Here's a great set of tutorials.

Resources