NSDate *start = [NSDate date];
// do stuff...
NSTimeInterval timeInterval = [start timeIntervalSinceNow];
timeInterval
is the difference between start and now, in seconds, with sub-millisecond precision.
You should not rely on [NSDate date]
for timing purposes since it can over- or under-report the elapsed time. There are even cases where your computer will seemingly time-travel since the elapsed time will be negative! (E.g. if the clock moved backwards during timing.)
According to Aria Haghighi in the "Advanced iOS Gesture Recognition" lecture of the Winter 2013 Stanford iOS course (34:00), you should use CACurrentMediaTime()
if you need an accurate time interval.
Objective-C:
#import <QuartzCore/QuartzCore.h>
CFTimeInterval startTime = CACurrentMediaTime();
// perform some action
CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;
Swift:
let startTime = CACurrentMediaTime()
// perform some action
let elapsedTime = CACurrentMediaTime() - startTime
The reason is that [NSDate date]
syncs on the server, so it could lead to "time-sync hiccups" which can lead to very difficult-to-track bugs. CACurrentMediaTime()
, on the other hand, is a device time that doesn't change with these network syncs.
You will need to add the QuartzCore framework to your target's settings.
Note: There are other API's like clock_gettime_nsec_np
that may work as well.
Use the timeIntervalSinceDate
method
NSTimeInterval secondsElapsed = [secondDate timeIntervalSinceDate:firstDate];
NSTimeInterval
is just a double
, define in NSDate
like this:
typedef double NSTimeInterval;
For anybody coming here looking for a getTickCount() implementation for iOS, here is mine after putting various sources together.
Previously I had a bug in this code (I divided by 1000000 first) which was causing some quantisation of the output on my iPhone 6 (perhaps this was not an issue on iPhone 4/etc or I just never noticed it). Note that by not performing that division first, there is some risk of overflow if the numerator of the timebase is quite large. If anybody is curious, there is a link with much more information here: https://stackoverflow.com/a/23378064/588476
In light of that information, maybe it is safer to use Apple's function CACurrentMediaTime
!
I also benchmarked the mach_timebase_info
call and it takes approximately 19ns on my iPhone 6, so I removed the (not threadsafe) code which was caching the output of that call.
#include <mach/mach.h>
#include <mach/mach_time.h>
uint64_t getTickCount(void)
{
mach_timebase_info_data_t sTimebaseInfo;
uint64_t machTime = mach_absolute_time();
// Convert to milliseconds
mach_timebase_info(&sTimebaseInfo);
machTime *= sTimebaseInfo.numer;
machTime /= sTimebaseInfo.denom;
machTime /= 1000000; // convert from nanoseconds to milliseconds
return machTime;
}
Do be aware of the potential risk of overflow depending on the output of the timebase call. I suspect (but do not know) that it might be a constant for each model of iPhone. on my iPhone 6 it was 125/3
.
The solution using CACurrentMediaTime()
is quite trivial:
uint64_t getTickCount(void)
{
double ret = CACurrentMediaTime();
return ret * 1000;
}
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With