Время истекло в Objective-C - PullRequest
150 голосов
/ 12 апреля 2009

Мне нужно, чтобы прошло время между двумя событиями, например, появлением UIView и первой реакцией пользователя.

Как мне достичь этого в Objective-C?

Ответы [ 7 ]

261 голосов
/ 12 апреля 2009
NSDate *start = [NSDate date];
// do stuff...
NSTimeInterval timeInterval = [start timeIntervalSinceNow];

timeInterval - это разница между началом и временем в секундах с точностью до миллисекунды.

220 голосов
/ 01 августа 2013

Вы не должны полагаться на [NSDate date] для целей синхронизации, так как это может привести к завышению или занижению прошедшего времени. Есть даже случаи, когда ваш компьютер будет путешествовать во времени, поскольку прошедшее время будет отрицательным! (Например, если часы переместились назад во время хронометража.)

Согласно Арии Хагиги в лекции «Расширенное распознавание жестов iOS» на курсе Winter 2013 Stanford iOS (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 framework к настройкам вашей цели.

23 голосов
/ 09 июля 2009

Используйте метод timeIntervalSinceDate

NSTimeInterval secondsElapsed = [secondDate timeIntervalSinceDate:firstDate];

NSTimeInterval это просто double, определите в NSDate как это:

typedef double NSTimeInterval;
15 голосов
/ 21 мая 2012

Для тех, кто приезжает сюда в поисках реализации 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;
}
8 голосов
/ 12 апреля 2009

Для измерения времени точного измерения (например, GetTickCount) также взгляните на mach_absolute_time и вопросы и ответы Apple: http://developer.apple.com/qa/qa2004/qa1398.html.

4 голосов
/ 12 апреля 2009

используйте функцию timeIntervalSince1970 класса NSDate, как показано ниже:

double start = [startDate timeIntervalSince1970];
double end = [endDate timeIntervalSince1970];
double difference = end - start;

По сути, это то, что я использую, чтобы сравнить разницу в секундах между двумя разными датами. Также проверьте эту ссылку здесь

0 голосов
/ 12 сентября 2013

Остальные ответы верны (с оговоркой *). Я добавляю этот ответ просто, чтобы показать пример использования:

- (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 время может прыгнуть вперед или назад в любой момент.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...