Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/objective-c/25.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Iphone 如何获得精确的时间,例如Objective-C中的毫秒?_Iphone_Objective C_Cocoa Touch_Uikit - Fatal编程技术网

Iphone 如何获得精确的时间,例如Objective-C中的毫秒?

Iphone 如何获得精确的时间,例如Objective-C中的毫秒?,iphone,objective-c,cocoa-touch,uikit,Iphone,Objective C,Cocoa Touch,Uikit,有没有一种简单的方法可以非常精确地得到时间 我需要计算方法调用之间的延迟。更具体地说,我想计算UIScrollView中的滚动速度。以双精度值返回绝对时间,但我不知道它的精度是多少--它可能只每十几毫秒更新一次,也可能每微秒更新一次,我不知道。NSDate和timeIntervalSince*方法将返回一个NSTimeInterval值,该值为精度为亚毫秒的双精度值NSTimeInterval以秒为单位,但它使用双精度来提高精度 要计算毫秒时间精度,可以执行以下操作: // Get a curr

有没有一种简单的方法可以非常精确地得到时间


我需要计算方法调用之间的延迟。更具体地说,我想计算UIScrollView中的滚动速度。

双精度值返回绝对时间,但我不知道它的精度是多少--它可能只每十几毫秒更新一次,也可能每微秒更新一次,我不知道。

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;

使用
NSDate
还有许多其他方法来计算此间隔,我建议查看
NSDate
的类文档,可以在中找到。

马赫绝对时间()
可用于获得精确的测量值

还提供了
CACurrentMediaTime()
,它本质上是相同的,但具有更易于使用的界面


(注意:这个答案是在2009年写的。请参阅Pavel Alexeev的答案,了解更新版本的macOS和iOS中更简单的POSIX
clock_gettime()
接口。)

此外,这里还介绍了如何以毫秒为单位计算用Unix历元初始化的64位
NSNumber
,在这种情况下,您希望将其存储在CoreData中。我的应用程序需要这个,它可以与一个以这种方式存储日期的系统进行交互

  + (NSNumber*) longUnixEpoch {
      return [NSNumber numberWithLongLong:[[NSDate date] timeIntervalSince1970] * 1000];
  }

我知道这是一个旧的,但即使我发现自己徘徊过去再次,所以我想我会提交我自己的选择在这里

最好的办法是查看我的博客文章:

基本上,我编写了一个类,它以一种非常基本的方式停止观看,但被封装,因此您只需要执行以下操作:

[MMStopwatchARC start:@"My Timer"];
// your work here ...
[MMStopwatchARC stop:@"My Timer"];
你最终会得到:

MyApp[4090:15203]  -> Stopwatch: [My Timer] runtime: [0.029]
在日志中

请再次查看我的帖子,获取更多信息或在此处下载:

我不会使用
mach\u absolute\u time()
,因为它使用滴答(可能是正常运行时间)查询内核和处理器的组合的绝对时间

我将使用:

CFAbsoluteTimeGetCurrent();
此功能经过优化以纠正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] -----------------------------------------------------
用法:

CTTimeStart();
...
CTTimeEnd(@"that was a long time:");
输出:

2013-08-23 15:34:39.558 App-Dev[21229:907] that was a long time: .0023

请不要使用
NSDate
CFAbsoluteTimeGetCurrent
gettimeofday
来测量经过的时间。这些都取决于系统时钟,由于许多不同的原因,系统时钟可能随时发生变化,例如网络时间同步(NTP)更新时钟(经常发生漂移调整)、DST调整、闰秒等

这意味着,如果你正在测量你的下载或上传速度,你的数字会突然上升或下降,这与实际发生的事情无关;您的性能测试将有奇怪的不正确的异常值;你的手动定时器会在不正确的持续时间后触发。时间甚至可能倒流,最终得到的是负增量,最终得到的可能是无限递归或死代码(是的,这两个我都做过)


使用
马赫绝对时间
。它测量内核启动后的实际秒数。它是单调递增的(永远不会倒退),不受日期和时间设置的影响。由于这是一个痛苦的工作,这里有一个简单的包装器,它为您提供
NSTimeInterval
s:

// 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
//LBClock.h
@接口LBClock:NSObject
+(instancetype)sharedClock;
//因为设备启动或其他原因。单调递增,不受日期和时间设置的影响
-(NSTimeInterval)绝对时间;
-(n时间间隔)绝对马赫数到时间间隔:(uint64_t)绝对马赫数;
@结束
//LBClock.m
#包括
#包括
@LBClock的实现
{
马赫时基信息数据时钟时基;
}
+(instancetype)sharedClock
{
静态LBClock*g;
静态调度一次;
一次发送(一次发送)^{
g=[LBClock new];
});
返回g;
}
-(id)init
{
if(!(self=[super init]))
返回零;
马赫时基信息(和时钟时基);
回归自我;
}
-(n时间间隔)绝对马赫数到时间间隔:(uint64_t)绝对马赫数
{
uint64\u t nanos=(绝对马赫数*\u clock\u timebase.numer)/\u clock\u timebase.denum;
返回nanos/1.0e9;
}
-(NSTimeInterval)绝对时间
{
uint64马赫时间=绝对马赫时间();
返回[自马赫绝对时间间隔:马赫时间];
}
@结束

对于那些我们需要@Jeff Thompson答案的快速版本的人:

// Get a current time for where you want to start measuring from
var date = NSDate()

// do work...

// Find elapsed time and convert to milliseconds
// Use (-) modifier to conversion since receiver is earlier than now
var timePassed_ms: Double = date.timeIntervalSinceNow * -1000.0

我希望这对您有所帮助。

您可以使用NSDate获取自1970年1月1日以来的当前时间(毫秒):

- (double)currentTimeInMilliseconds {
    NSDate *date = [NSDate date];
    return [date timeIntervalSince1970]*1000;
}

基于绝对马赫时间的函数适用于短时间测量。
但对于长时间的测量,重要的警告是,当设备处于睡眠状态时,它们会停止滴答声

有一个函数可以获取启动后的时间。睡觉时它不会停止。另外,
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(&currentTime, &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
}
总而言之:

  • Date.timeintervalenceReferenceDate
    -系统时间变化时会发生变化,而不是单调变化
  • CFAbsoluteTimeGetCurrent()
    -不是单调的,可能会倒退
  • CACurrentMediaTime()
    -当设备处于睡眠状态时停止滴答声
  • timeSinceBoot()
    -不睡眠,但可能不是单调的
  • 时钟是单调的
    
    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(&currentTime, &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
    }
    
    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
        }
    }