Пожалуйста, не используйте NSDate
, CFAbsoluteTimeGetCurrent
или gettimeofday
для измерения прошедшего времени. Все они зависят от системных часов, которые могут меняться в любое время по многим различным причинам, таким как синхронизация сетевого времени (NTP), обновление часов (часто происходит с поправкой на смещение), настройки DST, скачок секунд и т. д.
Это означает, что если вы измеряете скорость загрузки или выгрузки, вы получите внезапные всплески или падения чисел, которые не коррелируют с тем, что произошло на самом деле; ваши тесты производительности будут иметь странные неправильные выбросы; и ваши ручные таймеры сработают после неправильной продолжительности. Время может даже пойти вспять, и вы получите отрицательные дельты, и вы можете получить бесконечную рекурсию или мертвый код (да, я сделал и то, и другое).
Используйте mach_absolute_time
. Он измеряет реальные секунды с момента загрузки ядра. Он монотонно увеличивается (никогда не пойдет назад) и не зависит от настроек даты и времени. Так как работать с этим больно, вот простая оболочка, которая дает вам 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