Tha*_*nks 97 iphone cocoa-touch objective-c uikit
是否有一种简单的方法可以非常精确地获得时间?
我需要计算方法调用之间的一些延迟.更具体地说,我想计算UIScrollView中滚动的速度.
Jef*_*son 127
NSDate
并且timeIntervalSince*
方法将返回一个NSTimeInterval
具有亚毫秒精度的双精度.NSTimeInterval
是以秒为单位,但它使用双精度来提供更高的精度.
为了计算毫秒时间精度,您可以:
// Get a current time for where you want to start measuring from
NSDate *date = [NSDate date];
// do work...
// Find elapsed time and convert to milliseconds
// Use (-) modifier to conversion since receiver is earlier than now
double timePassed_ms = [date timeIntervalSinceNow] * -1000.0;
Run Code Online (Sandbox Code Playgroud)
有许多其他方法可以使用计算此间隔NSDate
,我建议查看NSDate
在NSDate类参考中找到的类文档.
Kri*_*son 40
mach_absolute_time()
可用于获得精确的测量结果.
请参阅http://developer.apple.com/qa/qa2004/qa1398.html
也可用CACurrentMediaTime()
,它本质上是相同的东西,但具有更易于使用的界面.
nev*_*vyn 26
请不要使用NSDate
,CFAbsoluteTimeGetCurrent
或gettimeofday
测量经过的时间.这些都依赖于系统时钟,它可以在改变任何时间,由于许多不同的原因,诸如网络时间同步(NTP)更新时钟(经常发生以调整漂移),DST调整,闰秒,等等.
这意味着,如果您正在测量下载或上传速度,您的数字会突然出现峰值或下降,与实际发生的情况无关; 你的性能测试会有奇怪的错误异常值; 并且您的手动计时器将在不正确的持续时间后触发.时间甚至可能倒退,你最终得到负增量,你最终会得到无限递归或死代码(是的,我已经完成了这两个).
使用mach_absolute_time
.它测量自内核启动以来的实际秒数.它是单调增加的(永远不会倒退),并且不受日期和时间设置的影响.由于使用它很痛苦,这里有一个简单的包装器,它可以为你提供NSTimeInterval
:
// LBClock.h
@interface LBClock : NSObject
+ (instancetype)sharedClock;
// since device boot or something. Monotonically increasing, unaffected by date and time settings
- (NSTimeInterval)absoluteTime;
- (NSTimeInterval)machAbsoluteToTimeInterval:(uint64_t)machAbsolute;
@end
// LBClock.m
#include <mach/mach.h>
#include <mach/mach_time.h>
@implementation LBClock
{
mach_timebase_info_data_t _clock_timebase;
}
+ (instancetype)sharedClock
{
static LBClock *g;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
g = [LBClock new];
});
return g;
}
- (id)init
{
if(!(self = [super init]))
return nil;
mach_timebase_info(&_clock_timebase);
return self;
}
- (NSTimeInterval)machAbsoluteToTimeInterval:(uint64_t)machAbsolute
{
uint64_t nanos = (machAbsolute * _clock_timebase.numer) / _clock_timebase.denom;
return nanos/1.0e9;
}
- (NSTimeInterval)absoluteTime
{
uint64_t machtime = mach_absolute_time();
return [self machAbsoluteToTimeInterval:machtime];
}
@end
Run Code Online (Sandbox Code Playgroud)
Ada*_*eld 14
CFAbsoluteTimeGetCurrent()
将绝对时间作为double
值返回,但我不知道它的精度是什么 - 它可能每十几毫秒更新一次,或者它可能每微秒更新一次,我不知道.
Nat*_*mer 10
我不会使用,mach_absolute_time()
因为它使用ticks(可能是正常运行时间)查询内核和处理器的组合绝对时间.
我会用什么:
CFAbsoluteTimeGetCurrent();
Run Code Online (Sandbox Code Playgroud)
此功能经过优化,可以纠正iOS和OSX软件和硬件的差异.
有点怪人
差异的商mach_absolute_time()
和AFAbsoluteTimeGetCurrent()
总是大约24000011.154871
这是我的应用程序的日志:
请注意,最终结果时间是不同CFAbsoluteTimeGetCurrent()
的
2012-03-19 21:46:35.609 Rest Counter[3776:707] First Time: 353900795.609040
2012-03-19 21:46:36.360 Rest Counter[3776:707] Second Time: 353900796.360177
2012-03-19 21:46:36.361 Rest Counter[3776:707] Final Result Time (difference): 0.751137
2012-03-19 21:46:36.363 Rest Counter[3776:707] Mach absolute time: 18027372
2012-03-19 21:46:36.365 Rest Counter[3776:707] Mach absolute time/final time: 24000113.153295
2012-03-19 21:46:36.367 Rest Counter[3776:707] -----------------------------------------------------
2012-03-19 21:46:43.074 Rest Counter[3776:707] First Time: 353900803.074637
2012-03-19 21:46:43.170 Rest Counter[3776:707] Second Time: 353900803.170256
2012-03-19 21:46:43.172 Rest Counter[3776:707] Final Result Time (difference): 0.095619
2012-03-19 21:46:43.173 Rest Counter[3776:707] Mach absolute time: 2294833
2012-03-19 21:46:43.175 Rest Counter[3776:707] Mach absolute time/final time: 23999753.727777
2012-03-19 21:46:43.177 Rest Counter[3776:707] -----------------------------------------------------
2012-03-19 21:46:46.499 Rest Counter[3776:707] First Time: 353900806.499199
2012-03-19 21:46:55.017 Rest Counter[3776:707] Second Time: 353900815.016985
2012-03-19 21:46:55.018 Rest Counter[3776:707] Final Result Time (difference): 8.517786
2012-03-19 21:46:55.020 Rest Counter[3776:707] Mach absolute time: 204426836
2012-03-19 21:46:55.022 Rest Counter[3776:707] Mach absolute time/final time: 23999996.639500
2012-03-19 21:46:55.024 Rest Counter[3776:707] -----------------------------------------------------
Run Code Online (Sandbox Code Playgroud)
#define CTTimeStart() NSDate * __date = [NSDate date]
#define CTTimeEnd(MSG) NSLog(MSG " %g",[__date timeIntervalSinceNow]*-1)
Run Code Online (Sandbox Code Playgroud)
用法:
CTTimeStart();
...
CTTimeEnd(@"that was a long time:");
Run Code Online (Sandbox Code Playgroud)
输出:
2013-08-23 15:34:39.558 App-Dev[21229:907] that was a long time: .0023
Run Code Online (Sandbox Code Playgroud)
基于的函数适用于mach_absolute_time
短期测量。
但是对于长时间的测量,重要的警告是当设备处于睡眠状态时它们会停止滴答作响。
有一个功能可以获取自启动以来的时间。它不会在睡觉时停止。此外,gettimeofday
不是单调的,但在我的实验中,我总是看到当系统时间改变时启动时间也会改变,所以我认为它应该可以正常工作。
func timeSinceBoot() -> TimeInterval
{
var bootTime = timeval()
var currentTime = timeval()
var timeZone = timezone()
let mib = UnsafeMutablePointer<Int32>.allocate(capacity: 2)
mib[0] = CTL_KERN
mib[1] = KERN_BOOTTIME
var size = MemoryLayout.size(ofValue: bootTime)
var timeSinceBoot = 0.0
gettimeofday(¤tTime, &timeZone)
if sysctl(mib, 2, &bootTime, &size, nil, 0) != -1 && bootTime.tv_sec != 0 {
timeSinceBoot = Double(currentTime.tv_sec - bootTime.tv_sec)
timeSinceBoot += Double(currentTime.tv_usec - bootTime.tv_usec) / 1000000.0
}
return timeSinceBoot
}
Run Code Online (Sandbox Code Playgroud)
从 iOS 10 和 macOS 10.12 开始,我们可以使用 CLOCK_MONOTONIC:
if #available(OSX 10.12, *) {
var uptime = timespec()
if clock_gettime(CLOCK_MONOTONIC_RAW, &uptime) == 0 {
return Double(uptime.tv_sec) + Double(uptime.tv_nsec) / 1000000000.0
}
}
Run Code Online (Sandbox Code Playgroud)
把它们加起来:
Date.timeIntervalSinceReferenceDate
— 随系统时间变化而变化,而不是单调的CFAbsoluteTimeGetCurrent()
— 不单调,可能会倒退CACurrentMediaTime()
- 当设备处于睡眠状态时停止滴答timeSinceBoot()
— 不睡觉,但可能不是单调的CLOCK_MONOTONIC
— 不休眠,单调,自 iOS 10 起支持此外,这里是如何以NSNumber
毫秒为单位计算使用 Unix 纪元初始化的 64 位,以防您希望将其存储在 CoreData 中。我的应用程序需要这个,它与以这种方式存储日期的系统交互。
+ (NSNumber*) longUnixEpoch {
return [NSNumber numberWithLongLong:[[NSDate date] timeIntervalSince1970] * 1000];
}
Run Code Online (Sandbox Code Playgroud)