Есть ли простой способ очень точно узнать время?
Мне нужно рассчитать некоторые задержки между вызовами методов. В частности, я хочу рассчитать скорость прокрутки в UIScrollView.
iphone
objective-c
cocoa-touch
uikit
Спасибо
источник
источник
Ответы:
NSDate
иtimeIntervalSince*
методы вернутNSTimeInterval
двойной с точностью до миллисекунды.NSTimeInterval
измеряется в секундах, но для большей точности используется значение double.Чтобы рассчитать точность времени в миллисекундах, вы можете:
Документация по timeIntervalSinceNow .
Есть много других способов вычислить этот интервал с помощью
NSDate
, и я бы рекомендовал посмотреть документацию по классам, дляNSDate
которых можно найти в NSDate Class Reference .источник
NSDate
иmach_absolute_time()
на уровне 30 мс. 27 против 29, 36 против 39, 43 против 45.NSDate
Мне было проще использовать, и результаты были достаточно похожи, чтобы не волноваться.mach_absolute_time()
можно использовать для получения точных измерений.См. Http://developer.apple.com/qa/qa2004/qa1398.html.
Также доступно
CACurrentMediaTime()
, что по сути то же самое, но с более простым в использовании интерфейсом.(Примечание: этот ответ был написан в 2009 году. См. Ответ Павла Алексеева о более простых
clock_gettime()
интерфейсах POSIX, доступных в более новых версиях macOS и iOS.)источник
CACurrentMediaTime()
, который преобразуетсяmach_absolute_time()
непосредственно в файлdouble
.elapsedNano
имеет типNanoseconds
, который не является простым целочисленным типом. Это псевдонимUnsignedWide
, который представляет собой структуру с двумя 32-битными целочисленными полями. Вы можете использоватьUnsignedWideToUInt64()
вместо литья, если хотите.Пожалуйста, не используйте
NSDate
,CFAbsoluteTimeGetCurrent
илиgettimeofday
для измерения прошедшего времени. Все это зависит от системных часов, которые могут измениться в любое время из-за множества различных причин, таких как синхронизация сетевого времени (NTP), обновляющая часы (часто происходит с корректировкой дрейфа), настройки летнего времени, дополнительные секунды и т. Д.Это означает, что если вы измеряете скорость загрузки или выгрузки, вы получите внезапные всплески или падения ваших чисел, которые не коррелируют с тем, что произошло на самом деле; ваши тесты производительности будут иметь странные неправильные выбросы; и ваши ручные таймеры сработают после неправильной продолжительности. Время может даже пойти в обратном направлении, и вы получите отрицательные дельты, и вы можете получить бесконечную рекурсию или мертвый код (да, я сделал и то, и другое).
Используйте
mach_absolute_time
. Он измеряет реальные секунды с момента загрузки ядра. Он монотонно увеличивается (никогда не возвращается назад) и не зависит от настроек даты и времени. Поскольку работать с этим сложно, вот простая оболочка, которая дает вамNSTimeInterval
:источник
CACurrentMediaTime()
QuartzCore?@import Darwin;
вместо#include <mach/mach_time.h>
CFAbsoluteTimeGetCurrent()
возвращает абсолютное время какdouble
значение, но я не знаю, какова его точность - он может обновляться только каждые дюжину миллисекунд или может обновляться каждую микросекунду, я не знаю.источник
72.89674947369
секунд было бы довольно необычным, учитывая все другие значения, которые могут быть. ;)Я бы НЕ использовал,
mach_absolute_time()
потому что он запрашивает комбинацию ядра и процессора в течение абсолютного времени, используя тики (возможно, время безотказной работы).Что бы я использовал:
Эта функция оптимизирована для исправления различий в программном и аппаратном обеспечении iOS и OSX.
Что-то более интересное
Частное от разницы в
mach_absolute_time()
иAFAbsoluteTimeGetCurrent()
всегда составляет около 24000011,154871.Вот журнал моего приложения:
Пожалуйста , обратите внимание , что последний раз результата является разницей в
CFAbsoluteTimeGetCurrent()
-хисточник
mach_absolute_time()
с a,mach_timebase_info_data
а затем сделал(long double)((mach_absolute_time()*time_base.numer)/((1000*1000)*time_base.denom));
. Чтобы получить(void)mach_timebase_info(&your_timebase);
Использование:
Вывод:
источник
NSDate
зависит от системных часов, которые можно изменить в любой момент, что может привести к неправильным или даже отрицательным временным интервалам. Используйтеmach_absolute_time
вместо этого, чтобы узнать истекшее время.mach_absolute_time
может повлиять на перезагрузку устройства. Вместо этого используйте серверное время.Кроме того, вот как рассчитать 64-битную,
NSNumber
инициализированную эпохой Unix, в миллисекундах, если вы хотите сохранить ее в CoreData именно так. Мне это нужно для моего приложения, которое взаимодействует с системой, которая таким образом хранит даты.источник
Функции на основе
mach_absolute_time
хороши для коротких измерений.Но для длительных измерений важен нюанс: они перестают тикать, пока устройство находится в спящем режиме.
Есть функция получения времени с момента загрузки. Это не прекращается во время сна. Кроме того,
gettimeofday
это не монотонно, но в своих экспериментах я всегда видел, что время загрузки изменяется при изменении системного времени, поэтому я думаю, что он должен работать нормально.А начиная с iOS 10 и macOS 10.12 мы можем использовать CLOCK_MONOTONIC:
Подвести итог:
Date.timeIntervalSinceReferenceDate
- меняется при изменении системного времени, не монотонноCFAbsoluteTimeGetCurrent()
- не монотонно, может идти назадCACurrentMediaTime()
- перестает тикать, когда устройство спитtimeSinceBoot()
- не спит, но может быть не монотоннымCLOCK_MONOTONIC
- не спит, монотонно, поддерживается с iOS 10источник
Я знаю, что это старый, но даже я обнаружил, что снова блуждаю мимо него, поэтому я решил представить здесь свой собственный вариант.
Лучше всего проверить мою запись в блоге об этом: Расчет времени в Objective-C: секундомер
По сути, я написал класс, который перестает смотреть в очень простом виде, но инкапсулирован, так что вам нужно сделать только следующее:
И вы получите:
в журнале ...
Опять же, ознакомьтесь с моим сообщением, чтобы узнать больше, или загрузите его здесь: MMStopwatch.zip
источник
NSDate
зависит от системных часов, которые можно изменить в любой момент, что может привести к неправильным или даже отрицательным временным интервалам. Используйтеmach_absolute_time
вместо этого, чтобы узнать истекшее время.Вы можете получить текущее время в миллисекундах с 1 января 1970 года, используя NSDate:
источник
Для тех, кто нам нужен Swift-версия ответа @Jeff Thompson:
Надеюсь, это вам поможет.
источник
NSDate
зависит от системных часов, которые можно изменить в любой момент, что может привести к неправильным или даже отрицательным временным интервалам. Используйтеmach_absolute_time
вместо этого, чтобы узнать истекшее время.