Как я могу получить точное время, например, в миллисекундах в Objective-C?

Есть ли простой способ получить точное время?

Мне нужно рассчитать некоторые задержки между вызовами метода. В частности, я хочу рассчитать скорость прокрутки в 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; 

Документация по времениIntervalSinceNow .

Существует много других способов расчета этого интервала с использованием NSDate , и я бы рекомендовал посмотреть документацию classа для NSDate которая содержится в NSDate Class Reference .

Для получения точных измерений можно использовать mach_absolute_time() .

См. http://developer.apple.com/qa/qa2004/qa1398.html

Также доступен CACurrentMediaTime() , что по сути то же самое, но с более простым в использовании интерфейсом.

Пожалуйста, не используйте NSDate , CFAbsoluteTimeGetCurrent или gettimeofday для измерения прошедшего времени. Все это зависит от системных часов, которые могут меняться в любое время по многим причинам, например, синхронизация времени в сети (NTP), обновляющая часы (часто приходится настраивать для дрейфа), регулировки DST, секунды прыжка и т. Д.

Это означает, что если вы измеряете скорость загрузки или выгрузки, вы получите внезапные всплески или падения в ваших номерах, которые не коррелируют с тем, что на самом деле произошло; ваши тесты производительности будут иметь странные неправильные выбросы; и ваши ручные таймеры будут срабатывать после неправильной продолжительности. Время может даже вернуться назад, и вы окажетесь в отрицательных дельтах, и вы можете обрести бесконечную рекурсию или мертвый код (да, я сделал это оба).

Используйте mach_absolute_time . Он измеряет реальные секунды с момента загрузки ядра. Он monoтонно увеличивается (никогда не будет возвращаться назад) и не зависит от настроек даты и времени. Поскольку это боль для работы, вот простая shell, которая дает вам 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  #include  @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 

CFAbsoluteTimeGetCurrent() возвращает абсолютное время как double значение, но я не знаю, какова его точность: он может обновляться только каждые дюжины миллисекунд или может обновлять каждую микросекунду, я не знаю.

Я бы не использовал mach_absolute_time() потому что он запрашивает комбинацию ядра и процессора в течение абсолютного времени с использованием тиков (возможно, время безотказной работы).

Что я буду использовать:

 CFAbsoluteTimeGetCurrent(); 

Эта функция оптимизирована для исправления различий в программном и аппаратном обеспечении iOS и OSX.

Что-то Geekier

Фактор разницы в 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] ----------------------------------------------------- 
 #define CTTimeStart() NSDate * __date = [NSDate date] #define CTTimeEnd(MSG) NSLog(MSG " %g",[__date timeIntervalSinceNow]*-1) 

Применение:

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

Вывод:

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

Кроме того, вот как вычислить 64-разрядный NSNumber инициализированный с эпохой Unix в миллисекундах, в случае, если вы хотите сохранить его в CoreData. Мне это нужно для моего приложения, которое взаимодействует с системой, которая хранит даты таким образом.

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

Я знаю, что это старый, но даже я обнаружил, что снова блуждаю по нему, поэтому я подумал, что я предлагаю свой вариант здесь.

Лучше всего проверить мой пост в блоге по этому поводу : Сроки в Objective-C: секундомер

В принципе, я написал class, который перестает смотреть очень простым способом, но инкапсулирован так, что вам нужно только сделать следующее:

 [MMStopwatchARC start:@"My Timer"]; // your work here ... [MMStopwatchARC stop:@"My Timer"]; 

И вы получите:

 MyApp[4090:15203] -> Stopwatch: [My Timer] runtime: [0.029] 

в журнале …

Опять же, просмотрите мой пост еще немного или загрузите его здесь: MMStopwatch.zip

Функции, основанные на mach_absolute_time , хороши для коротких измерений.
Но для длительных измерений важно остерегаться того, что они перестают тикать, пока устройство спит.

Существует функция получения времени с момента загрузки. Он не останавливается во время сна. Кроме того, gettimeofday не является monoтонным, но в моих экспериментах я всегда вижу, что время загрузки изменяется при изменении системного времени, поэтому я думаю, что он должен работать нормально.

 func timeSinceBoot() -> TimeInterval { var bootTime = timeval() var currentTime = timeval() var timeZone = timezone() let mib = UnsafeMutablePointer.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 } 

А поскольку 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 } } 

Подвести итог:

  • Date.timeIntervalSinceReferenceDate – изменяется при изменении системного времени, а не monoтонном
  • CFAbsoluteTimeGetCurrent() – не monoтонно, может идти назад
  • CACurrentMediaTime() – останавливает тикинг, когда устройство спит
  • timeSinceBoot() – не спит, но может быть не monoтонным
  • CLOCK_MONOTONIC – не спит, monoтонно поддерживается с iOS 10

Для тех, кому нужна быстрая версия ответа @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 

Надеюсь, это поможет вам.

Вы можете получить текущее время в миллисекундах с 1 января 1970 года, используя NSDate:

 - (double)currentTimeInMilliseconds { NSDate *date = [NSDate date]; return [date timeIntervalSince1970]*1000; } 
  • установить фоновое изображение для всего приложения iPhone / iPad
  • Автоматически запускать локальные уведомления ежедневно в динамическое время, заданное в массивах. objective ios
  • запись NSDictionary для plist в моем приложении
  • Невозможно добавить элементы в NSMutableArray ivar
  • Ошибка UIActivityViewController на iOS 8 iPads
  • Содержимое HTML соответствует UIWebview без масштабирования
  • Центральное содержимое UIScrollView при меньшем
  • Замена на устаревший размерWithFont: в iOS 7?
  • Как отменить 2 Modal View Controllers в последовательности?
  • Как вы вычисляете день года на определенную дату в Objective-C?
  • Получить нажатие кнопки внутри UITableViewCell
  • Давайте будем гением компьютера.