ios: find real time since previous app launch - ios

SO basically all is in the title. I've searched quite a lot, but didn't find any right solution which doesn't require internet connection.
If the user changes time in settings - i can't find real time since last launch.
I need that for my game, in it for every hour, even when you don't play the game, you get some coins.
If the user changes time in settings - that affect the time in NSDate() and user can cheat with coins.

So save the NSDate() to user defaults on app launch. The next time the app comes to the foreground, or gets launched again, get the current NSDate and subtract the saved date from it. That will give you the number of seconds between the two dates. Calculating hours from seconds is a simple matter of dividing by 3600. – Duncan C just now edit
EDIT:
Note that in newer versions of Swift (starting with Swift 2?) Most Foundation classes were defined as native Swift classes without the NS prefix. For newer versions of swift, replace all occurrences of NSDate with Date in the above.
Also note that in iOS ≥ 7.0, the Calendar has some methods that make this sort of calculation neater and easier. There's a new method dateComponents(_:from:to:) that lets you calculate the difference between 2 dates in whatever units you want. You could use that to calculate the seconds between the 2 dates more cleanly than calculating seconds, as outlined in my original answer. Calendar methods also tend to handle boundary conditions like spanning daylight savings time, leap seconds, etc.
Consider the following Swift 4/5 playground code:
import UIKit
let now = Date()
let randomSeconds = Double.random(in: 100000...3000000)
let later = now + randomSeconds
if let difference = Calendar.current.dateComponents([.second],
from: now,
to: later)
.second {
print(difference)

Try this.
Step 1. When user exits game. Set a NSUserDefault with current time.
Step 2. When app launches, in your appDelagate file, get this value.
Step 3. Calculate diff between and award coins accordingly.

Related

iOS clock animations on homescreen widget

I want to add a homescreen widget to my app, just like the iOS system Clock app, the second hand keeps moving every second. I have been searching on Google and Github for a long time and have not found a suitable solution. I have seen that there are already third-party apps that can implement such desktop widgets. For example:
How do they do it?
Use View._clockHandRotationEffect(.secondHand, in: .current, anchor: .center)
According to Apple it can't be done.
Here you can find a comment made by a Systems Engineer from Apple:
[...] However, you cannot update views to the time other than the relative date text label. So you cannot replicate the Clock widget for example and have second hands on a clock tick by while the widget is visible. Sorry.
Also, from the Human Interface Guidelines for Widgets:
Keep your widget up-to-date. To remain relevant and useful, widgets should periodically refresh their information. Widgets don’t support continuous, real-time updates, and the system may adjust the limits for updates depending on various factors.
My understanding is that the only way for third-party apps to provide such animations is to use private API. The system Clock Widget does this after all, so it might actually be possible to replicate this behaviour using some private methods that I'm not aware of.
If you're interested in exploring some more shady corners of SwiftUI, this post might get you started:
Is there a way to find actual SwiftUI API Documentation (and not just the developer documentation)?
Apple has a whole page on how to display dynamic Dates.
The WWDC20 widgets code-along example updates by the second. Their timeline entires are every minute.
Using a Text view in your widget, you can display dates and times that stay up to date onscreen. The following examples show the combinations available.
To display a relative time that updates automatically:
let components = DateComponents(minute: 11, second: 14)
let futureDate = Calendar.current.date(byAdding: components, to: Date())!
Text(futureDate, style: .relative)
// Displays:
// 11 min, 14 sec
Text(futureDate, style: .offset)
// Displays:
// -11 minutes
For dates in the future, the timer style counts down until the current time reaches the specified date and time, and counts up when the date passes.
To display an absolute date or time:
// Absolute Date or Time
let components = DateComponents(year: 2020, month: 4, day: 1, hour: 9, minute: 41)
let aprilFirstDate = Calendar.current(components)!
Text(aprilFirstDate, style: .date)
Text("Date: \(aprilFirstDate, style: .date)")
Text("Time: \(aprilFirstDate, style: .time)")
The idea is to simply spam WidgetCenter.shared.reloadAllTimelines() every tick. Check this repo: https://github.com/lexrus/LexClockWidget

Response Time in Robot Framework

Is there any way to know the time taken for each action to finish in Robot Framework???
Like For example, I want to rotate screen 90 degrees 10 times, how to time it or how to average the time taken by these actions??
The simplest solution is to get the current time, run your keyword or keywords, then get the current time again, Then, subtract the starting time from the ending time.
Robot framework provides a DateTime module that has functions to support this. For example, Get current date can return the current date and time. Subtract date from date can return a timedelta which can be formatted to days, hours, minutes, seconds, and milliseconds.
You can see it in your report.
http://robotframework.org/QuickStartGuide/report.html
Elapsed Time: 00:00:00.284
It is also available at Keyword Level in the Test Execution Log.
${date1} = Get Current Date
TestCase_To_Rotate_Screen_10_Times
${date2} = Get Current Date
${actiontime} = Subtract Date From Date ${date2} ${date1}

Run code every 24 hours, but only after a specific time

In my apps settings page, users can select to have their data cleared every day, either at 3am, or 3pm, depending on their schedule. Im looking for a way to reliably do this.
So far I have tried storing the seconds since Jan 1, 1970 on install, and then every time time app is opened, I get the current seconds since 1970, and compare them to determine if the number meets or exceeds 86400, which is 24 hours. If it does, I clear the data and replace the stored seconds with the time of the clear, and if it doesn't I do nothing. This would work great if I only wanted to clear the data if its been 24 hours or more since the last clear, but what I really want to do is clear the data if its past the users set time, and a clear hasn't already been completed that day.
For example:
if the app is installed on May 21st at 6pm, and the user begins to input data, it should clear as long as the current data & time meets or is past May 22nd, at 3am. The 24 hour logic will not not clear it until the date and time meets or exceeds May 22nd, at 6pm.
Any thoughts on how this could be accomplished?
Well i'm not sure how you are planning on handling it(with push notifications/Local notifications/ or a simple check if the user has the app in the foreground)
However, I would create a local notification:
let notification = UILocalNotification()
notification.fireDate = Date().addingTimeInterval(86400)
UIApplication.sharedApplication().scheduleLocalNotification(notification)
Handle your clearing, and reset the notifications for 24-hours later once again.
Silent push notifications would be nice, as you would be able to clear the data every 24 hours, without your user needing to think about or even open the app. However, you would then need backend logic to handle sending out those notifications to the devices; you are limiting your reset times to 3am or 3pm so I suppose that wouldn't be terrible to implement.
Just keep in mind that you are limited to a 30s runtime. Also the silent notifications only complete if the app is suspended, if the app has been terminated by the user, the delegate method is not called.
--Edit--
Push notifications would be a little much for this, I must have missed the part saying you wanted this to happen on app start(sorry about that)....
You could write a extension to the Date class:
func dateByAddingDays(_ daysToAdd: Int) -> Date {
let calendar = Calendar.current
var days = DateComponents()
days.day = daysToAdd
return (calendar as NSCalendar).date(byAdding: days, to: self, options: [])
}
Save this date however you would like, then on app load compare the saved date to the current date, if it passes your check remove the data. You don't have to use days here, you can can replace days with hours/minutes etc... var hours = DateComponents() -> hours.hour = hoursToAdd

Logarithmic calculation in Objective-C [duplicate]

This question already has answers here:
What kind of logarithm functions / methods are available in objective-c / cocoa-touch?
(3 answers)
Closed 9 years ago.
I am building a game using Sprite Kit and I want to gradually increase the difficulty (starting at 1.0) based on the time since starting the game.
Someone suggested that I should use a logarithmic calculation for this but I'm unsure how to implement this in Objective-C.
- (float)difficulty
{
timeSinceStart = ???; // I don't what kind of object this should be to make it play nice w/ `log`
return log(???);
}
Update #1
I know that I need to use the log method but I'm uncertain what values I need to pass to it.
Objective C is a superset of the C language, therefore you can use "math.h".
The function that computes the natural logarithm from "math.h" is double log(double x);
EDIT
Since you want the difficulty to increase as a function of time, you would pass the time as the argument to log(double x). How you would use that to calculate and change the "difficulty" is an entirely different question.
If you want to change the shape of the curve, either multiply the expression by a constant, as in 2*log(x) or multiply the parameter by a constant, as in log(2*x). You will have to look at the individual curves to see what will work best for your specific application.
Since log(1.0) == 0 you probably want to do some scaling and translation. Use something like 1.0 + log(1.0 + c * time). At time zero this will give a difficulty of 1.0, and as time advances the difficulty will increase at a progressively slower pace whose rate is determined by c. Small values such as c = 0.01 will give a slow ramp-up, larger values will ramp-up faster.
#pjs gave a pretty clear answer. As to how to figure out the time: You probably want the amount of time spent actually playing, rather than elapsed time since launching the game.
So you will nee to track total time played, game after game.
I suggest you create an entry in NSUserDefaults. You can save and load double values to user defaults using the NSUserDefaults methods setDouble:forKey: and doubleForKey:
I would create an instance variable startPlayingTime, type double
When you start the game action running, capture the start time using
startPlayingTime = [NSDate timeIntervalSinceReferenceDate];
When the user passes the game/exits to the background, use
NSTimeInterval currentPlayTime = [NSDate timeIntervalSinceReferenceDate] - startPlayingTime;
Then read the total time played from user defaults, add currentPlayTime to it, and save it back to user defaults.
You can then make your game difficulty based on
difficulty = log(1+ c * totalPlayTime);
(as explained by pjs, above) and pick some appropriate value for C.

iOS prevent date/time update?

a relatively simple question that I've not been able to find a clear answer to. My app is more complex, but answering this question will suffice.
Suppose you're writing a stopwatch app. When the user taps "start", the app stores the current date and time in startTime:
startTime = [NSDate date];
When the user tapes "stop", the app stores the current date and time in stopTime:
stopTime = [NSDate date];
The duration is calculated by:
duration = [stopTime timeIntervalSinceDate:startTime];
and is displayed with something like:
[durationLabel setText:[NSString stringWithFormat:#"%1.2f", duration]];
The typical durations that my app is timing range from 2 to 50 seconds. I need accuracy to 1/100th of a second (e.g. 2.86 seconds).
I'm assuming that there is some protocol that iOS devices use to keep their clocks accurate (cellular or NTP sources?). My concern is that between starting and stopping the stopwatch, the clock on the iOS device is updated which can result in a shift of the current date/time either ahead or back. If this were to happen, the duration calculated would be inaccurate.
I've seen a few posts relating to timing methods for purposes of improving code efficiency. Some suggest using mach_time.h functions, which I'm not familiar with. It's not obvious to me which is the best approach to use.
Is it possible to disable iOS from updating the date & time? Is mach_absolute_time() unaffected by iOS clock updates?
Many thanks!
Tim
You are correct in thinking that CFAbsoluteTime and its derivatives (NSDate dateand so on) are potentially skewed by network updates on 'real' time. Add that to the fact that NSTimer has an accuracy of 50-100ms and you have a timer that is not suited to the most critical of time-sensitive operations.
The answer to this problem seems to be CACurrentMediaTime.
It is a member of the Core Animation group, but there shouldn't be any problem integrating it into non-animation based applications.
CACurrentMediaTime is a wrapper of mach_absolute_time() and makes sense of the "mach absolute time unit," which from my understanding is no fun to tinker with. mach_absolute_time() is calculated by running a non-network synced timer since the device was last booted.
There is relatively little information on CACurrentMediaTime but here are some sources and further reading:
Apple's sparse documentation of CACurrentMediaTime
Stack Overflow - NSTimer vs CACurrentMediaTime()
http://bendodsonapps.com/weblog/2013/01/29/ca-current-media-time/
http://blog.spacemanlabs.com/2011/09/all-in-the-timing-keeping-track-of-time-passed-on-ios/
http://forum.sparrow-framework.org/topic/accurate-timer
Note: If you do use CACurrentMediaTime, make sure you include and link the QuartzCore.framework
Check out this here. I would say forget about the current time check and use a precision timer since it won't rely on the current time but instead uses an interval.

Resources