Мне нужно, чтобы прошло время между двумя событиями, например, появлением UIView и первой реакцией пользователя.
Как я могу достичь этого в Objective-C?
Мне нужно, чтобы прошло время между двумя событиями, например, появлением UIView и первой реакцией пользователя.
Как я могу достичь этого в Objective-C?
Ответы:
NSDate *start = [NSDate date];
// do stuff...
NSTimeInterval timeInterval = [start timeIntervalSinceNow];
timeInterval
это разница между началом и теперь, в секундах, с точностью до миллисекунды.
[NSDate date]
может привести к трудностям в отслеживании ошибок, см. Этот ответ для получения дополнительной информации.
Вы не должны полагаться на [NSDate date]
сроки, поскольку это может привести к завышению или занижению прошедшего времени. Есть даже случаи, когда ваш компьютер будет путешествовать во времени, поскольку прошедшее время будет отрицательным! (Например, если часы переместились назад во время синхронизации.)
Согласно Арии Хагиги в лекции «Расширенное распознавание жестов iOS» курса iOS 2013 года в Стэнфорде (34:00), вы должны использоватьCACurrentMediaTime()
если вам нужен точный интервал времени.
Objective-C:
#import <QuartzCore/QuartzCore.h>
CFTimeInterval startTime = CACurrentMediaTime();
// perform some action
CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;
Swift:
let startTime = CACurrentMediaTime()
// perform some action
let elapsedTime = CACurrentMediaTime() - startTime
Причина в том, что [NSDate date]
синхронизация на сервере такова, что это может привести к «сбоям синхронизации по времени», что может привести к очень трудным для отслеживания ошибкам.CACurrentMediaTime()
с другой стороны, это время устройства, которое не изменяется при этих сетевых синхронизации.
Вам нужно будет добавить платформу QuartzCore в настройки вашей цели.
[NSDate date]
внутри блока завершения в блоке отправки я получал то же самое «текущее» время, о котором сообщалось [NSDate date]
непосредственно перед тем, как выполнение достигло точки, в которой были созданы мои блоки. CACurrentMediaTime()
решил эту проблему.
CACurrentMediaTime()
виду, что перестает тикать, когда устройство переходит в режим сна. Если вы тестируете устройство, отключенное от компьютера, заблокируйте его, а затем подождите ~ 10 минут, и вы обнаружите, что CACurrentMediaTime()
оно не идет в ногу со временем настенных часов.
Используйте timeIntervalSinceDate
метод
NSTimeInterval secondsElapsed = [secondDate timeIntervalSinceDate:firstDate];
NSTimeInterval
это просто double
определить, NSDate
как это:
typedef double NSTimeInterval;
Для тех, кто приезжает сюда в поисках реализации getTickCount () для iOS, вот мое после объединения различных источников.
Ранее у меня была ошибка в этом коде (сначала я разделил на 1000000), которая приводила к некоторому количественному определению выходных данных на моем iPhone 6 (возможно, это не было проблемой на iPhone 4 / etc или я просто никогда этого не замечал). Обратите внимание, что если сначала не выполнить это деление, существует некоторый риск переполнения, если числитель временной базы достаточно велик. Если кому-то интересно, здесь есть ссылка с гораздо большей информацией: https://stackoverflow.com/a/23378064/588476
В свете этой информации, возможно, безопаснее использовать функцию Apple CACurrentMediaTime
!
Я также mach_timebase_info
протестировал вызов, и на моем iPhone 6 это заняло приблизительно 19 нс, поэтому я удалил (не поддерживающий потоки) код, который кэшировал выходные данные этого вызова.
#include <mach/mach.h>
#include <mach/mach_time.h>
uint64_t getTickCount(void)
{
mach_timebase_info_data_t sTimebaseInfo;
uint64_t machTime = mach_absolute_time();
// Convert to milliseconds
mach_timebase_info(&sTimebaseInfo);
machTime *= sTimebaseInfo.numer;
machTime /= sTimebaseInfo.denom;
machTime /= 1000000; // convert from nanoseconds to milliseconds
return machTime;
}
Помните о потенциальном риске переполнения в зависимости от выходных данных вызова временной базы. Я подозреваю (но не знаю), что она может быть постоянной для каждой модели iPhone. на моем айфоне 6 было 125/3
.
Использование решения CACurrentMediaTime()
довольно тривиально:
uint64_t getTickCount(void)
{
double ret = CACurrentMediaTime();
return ret * 1000;
}
mach_timebase_info()
сбросит переданный в mach_timebase_info_data_t
перед {0,0}
тем, как установить его в фактические значения, что может вызвать деление на ноль, если код вызывается из нескольких потоков. Используйте dispatch_once()
вместо этого (или CACurrentMediaTime
которое является просто временем Маха, преобразованным в секунды).
Для измерения времени точного прохождения (например, GetTickCount) также взгляните на mach_absolute_time и вопросы и ответы Apple: http://developer.apple.com/qa/qa2004/qa1398.html .
используйте функцию timeIntervalSince1970 класса NSDate, как показано ниже:
double start = [startDate timeIntervalSince1970];
double end = [endDate timeIntervalSince1970];
double difference = end - start;
в основном, это то, что я использую, чтобы сравнить разницу в секундах между двумя разными датами. также проверьте эту ссылку здесь
Другие ответы верны (с оговоркой *). Я добавляю этот ответ просто, чтобы показать пример использования:
- (void)getYourAffairsInOrder
{
NSDate* methodStart = [NSDate date]; // Capture start time.
// … Do some work …
NSLog(@"DEBUG Method %s ran. Elapsed: %f seconds.", __func__, -([methodStart timeIntervalSinceNow])); // Calculate and report elapsed time.
}
На консоли отладчика вы видите что-то вроде этого:
DEBUG Method '-[XMAppDelegate getYourAffairsInOrder]' ran. Elapsed: 0.033827 seconds.
* Предостережение: как уже упоминалось, используйте NSDate
для расчета прошедшего времени только для случайных целей. Одной из таких целей может быть обычное тестирование, грубое профилирование, когда вы просто хотите получить приблизительное представление о том, сколько времени занимает метод.
Риск состоит в том, что текущая установка времени устройства может измениться в любой момент из-за синхронизации сетевых часов. Так что NSDate
время может прыгать вперед или назад в любой момент.
fabs(...)
чтобы получить абсолютное значение с плавающей точкой. Например.NSTimeInterval timeInterval = fabs([start timeIntervalSinceNow]);