Get the length of time the iPhone was locked - ios

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
}

Related

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)

Execute custom method on UILocalNotification fire in iOS

I am working on Alarm module in my app. I have develop code which take date and time input from user and set Event on that particular time in my app.
Also i store information into my local database to display list of alarm set by user.
Now i want to delete entry from database when particular alarm executed (When UILocalNotification displayed into app i want to call database method to delete that entry from db)
I set Notification by this way
NSUserDefaults* preferences = [NSUserDefaults standardUserDefaults];
int notificationCount = [preferences integerForKey:#"notification_count"];
notificationCount++;
NSDate* final_date = [calendar dateFromComponents:final_Components];
UILocalNotification *localNotification = [[UILocalNotification alloc]init];
localNotification.fireDate = final_date;
localNotification.alertBody=titleTextField.text;localNotification.soundName = UILocalNotificationDefaultSoundName;
localNotification.timeZone = [NSTimeZone defaultTimeZone];
localNotification.applicationIconBadgeNumber = 1;
NSDictionary* userInfoDic = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:notificationCount] forKey:#"notification_id"]; localNotification.userInfo = userInfoDic;
localNotification.repeatInterval = 0;
[[UIApplication sharedApplication]scheduleLocalNotification:localNotification];
[preferences setInteger:notificationCount forKey:#"notification_count"];
I used Delegate didReceiveLocalNotification
-(void) application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *)notification
{
NSString *itemName = [notification.userInfo objectForKey:#"notification_id"];
NSLog(#"userInfo is %#",itemName);
databaseObject.deleteNotification(itemName)
}
My problem is "didReceiveLocalNotification" only call in 2 case
1) When user using app (app in foreground).
2) when notification displayed and user click on notification
But in 3rd case when app is in background mode and notification displayed and if user don't click on notification Or second case is open app directly clicking on app icon or user clear notification at that time didReceiveLocalNotification delegate is not get called..
Is there any way to detect Notification fire in all case or any other method by using i can detect that notification has been fire and then i will execute my delete method.
Any help is appreciated
Thank you
Yes, you are right, you won't know the information of the notification if your notification fires while your app is suspended/terminated and user didn't tap the notification to launch/active your app.
The only way to do this is to calculate the time every time your app is running and reschedule notifications and update your database.
For millisecond calculation:
NSInteger myMillisecond; //assume it exists
const NSTimeInterval oneSecondAsMilliseconds = 1000.0;
NSTimeInterval myTimeInterval = myMillisecond/oneSecondAsMilliseconds;
NSDate *currentDate = [NSDate date];
NSTimeInterval currentTimeStamp = [currentDate timeIntervalSince1970];
if (myTimeInterval > currentTimeStamp) {
//myTimeInterval is a later time than now
}

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.

detect unacknowledged UILocalNotifications

It seems that
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
and
didReceiveLocalNotification:(UILocalNotification *)notification
are only triggered if the user acknowledges the UILocalNotification, for example by swiping the slider or touching the entry in iOS's Notification pull-down.
Is there any way to tell that a UILocalNotification has gone off if the user ignores the UILocalNotification and re-enters the app by simply clicking on the app icon?
I should mention that this really only applies to repeating notifications because the firing of non-repeating notifications can be detected by observing the total count. That is, when they fire, the vanish from [[UIApplication sharedApplication] scheduledLocalNotifications].
I'm looking for something like..
[[UIApplication sharedApplication] unacknowledgedLocalNotifications]
Alas, I can't find anything like it.
Well, you can check your scheduled notifications inside [[UIApplication sharedApplication] scheduledLocalNotifications]. To find out if a scheduled repeating notification has fired access the fireDate property to see what was the initial date set for the notification. Then check the repeatInterval property.
So there you have 2 variables, one is the initial NSDate, lets say 2013-05-08 12:00 and second is the repeat interval, lets say daily. And by doing a [NSDate date] you will get the current date which where I'm located (in Sweden) is now 2013-05-09 22:45. So this means that there is one notification the user has not acted on.
So you will need to create a method that will take these arguments and then iterate from the initial date to see how many notifications that have been missed until the current datetime.
You will find NSCalendars dateByAddingComponents:toDate:options useful.
Everyone has likely since moved on, but I'd like to share my solution to this problem. (Sorry about the long variables names...)
The idea is simple: always keep the fireDate in the future.
-every time didFinishLaunchingWithOptions or didReceiveLocalNotification is invoked, simply cancel your current notification and reschedule a new one with a fireDate one interval unit in the future
-When your app launches iterate through all scheduled notifications, if the fireDate is not in the future you know that it was ignored
In my case, the notifications have a weekly repeat interval. I first reschedule any acknowledged notifications in didFinishLaunchingWithOptions:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UILocalNotification* localNotif = [launchOptions objectForKey:UIApplicationLaunchOptionsLocalNotificationKey];
if (localNotif != nil)
{
[NotificationsHelper rescheduleNotification:localNotif];
}
}
And also in didReceiveLocalNotification:
- (void)application:(UIApplication *)application didReceiveLocalNotification:(UILocalNotification *) notification
{
[NotificationsHelper rescheduleNotification:notification];
}
At App Launch I check all notifications for any with a fireDate in the past:
- (void)applicationDidBecomeActive:(UIApplication *)application
{
[self checkLocalNotifications:application];
}
Code for my "checkLocalNotifications" function:
- (void) checkLocalNotifications:(UIApplication *) application
{
UIApplication* app = [UIApplication sharedApplication];
NSArray* eventArray = [app scheduledLocalNotifications];
for (int i = 0; i < [eventArray count]; i++)
{
UILocalNotification* notification = [eventArray objectAtIndex:i];
if ([NotificationsHelper wasWeeklyRepeatingNotificationIgnored:notification])
{
[NotificationsHelper rescheduleNotification:notification];
NSLog(#"NotificationWasIgnored: %# %#",notification.alertAction, notification.alertBody );
}
}
}
Code for my "wasWeeklyRepeatingNotificationIgnored" function:
+ (BOOL) wasWeeklyRepeatingNotificationIgnored:(UILocalNotification*) the_notification
{
BOOL result;
NSDate* now = [NSDate date];
// FireDate is earlier than now
if ([the_notification.fireDate compare:now] == NSOrderedAscending)
{
result = TRUE;
}
else
{
result = FALSE;
}
return result;
}
Code for my "rescheduleNotification" function:
+ (void) rescheduleNotification:(UILocalNotification*) the_notification
{
UILocalNotification* new_notification = [[UILocalNotification alloc] init];
NSMutableDictionary* userinfo = [[NSMutableDictionary alloc] init];
[new_notification setUserInfo:userinfo];
[new_notification setRepeatInterval:the_notification.repeatInterval];
[new_notification setSoundName:UILocalNotificationDefaultSoundName];
[new_notification setTimeZone:[NSTimeZone defaultTimeZone]];
[new_notification setAlertAction:the_notification.alertAction];
[new_notification setAlertBody:the_notification.alertBody];
[new_notification setRepeatCalendar:[NSCalendar currentCalendar]];
[new_notification setApplicationIconBadgeNumber:the_notification.applicationIconBadgeNumber];
NSCalendar* gregorian = [[NSCalendar alloc] initWithCalendarIdentifier:NSGregorianCalendar];
NSDateComponents* weekdayComponents = [gregorian components:NSWeekdayCalendarUnit
fromDate:the_notification.fireDate];
NSInteger weekday = [weekdayComponents weekday];
NSDate* next_week = [self addDay:weekday toHourMinute:the_notification.fireDate];
[new_notification setFireDate:next_week];
[[UIApplication sharedApplication] scheduleLocalNotification:new_notification];
[[UIApplication sharedApplication] cancelLocalNotification:the_notification];
}
If your UILocalNotifications increment the application icon badge number (i.e. the number in the red circle on the top right of the app's icon), then there is a ridiculously simple way to check for unacknowledged UILocalNotifications: just check what the current applicationIconBadgeNumber is:
- (void)applicationWillEnterForeground:(UIApplication *)application
{
int unacknowledgedNotifs = application.applicationIconBadgeNumber;
NSLog(#"I got %d unacknowledged notifications", unacknowledgedNotifs);
//do something about it...
//You might want to reset the count afterwards:
[[UIApplication sharedApplication] setApplicationIconBadgeNumber:0];
}

iOS: Background / Foreground Events

I´m working on an application in which, when it is pushed in background via the home button, a timer should start and when the application gets back to foreground and the timer has passed a certain amount of time, something should be executed.
My questions are
How do I handle the events when my app goes to
background/foreground?
Is there a special method or an other technique?
Thanks a lot.
A possible implementation could look like:
#define YOUR_TIME_INTERVAL 60*60*5 //i.e. 5 hours
- (void)applicationDidEnterBackground:(UIApplication *)application
{
//... your oder code goes here
NSNumber *timeAppClosed = [NSNumber numberWithDouble:[[NSDate date] timeIntervalSince1970]];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
[defaults timeAppClosed forKey:#"time.app.closed"];
[defaults synchronize];
}
and
- (void)applicationWillEnterForeground:(UIApplication *)application
{
NSNumber *timeAppClosed = [[NSUserDefaults standardUserDefaults] valueForKey:#"time.app.closed"];
if(timeAppClosed == nil)
{
//No time was saved before so it is the first time the user
//opens the app
}
else if([[NSDate date] timeIntervalSinceDate:[NSDate dateWithTimeIntervalSince1970:[timeAppClosed doubleValue]]] > YOUR_TIME_INTERVAL)
{
//Place your code here
}
}
In the appDelegate of the app you have some delegate methods which you can implement.
You can check out the UIApplicationDelegate protocol to which you AppDelegate should conform.
When the app is pushed in the background the function applicationDidEnterBackground: will be called. When entering the foreground applicationWillEnterForeground: is called.
Better not use a timer, but store a NSDate reference in the applicationDidEnterBackground: method. When your app is entering the foreground you can calculate the timeDifference using the stored NSDate using the
- (NSTimeInterval)timeIntervalSinceDate:(NSDate *)anotherDate
function.

Resources