Мені потрібно пройти час між двома подіями, наприклад, появою UIView та першою реакцією користувача.
Як я можу досягти цього в Objective-C?
Мені потрібно пройти час між двома подіями, наприклад, появою UIView та першою реакцією користувача.
Як я можу досягти цього в Objective-C?
Відповіді:
NSDate *start = [NSDate date];
// do stuff...
NSTimeInterval timeInterval = [start timeIntervalSinceNow];
timeInterval
- це різниця між початком і зараз, у секундах, з субмілісекундною точністю.
[NSDate date]
може призвести до важкого відстеження помилок, див. Цю відповідь для отримання додаткової інформації.
Не слід покладатися на [NSDate date]
часові цілі, оскільки це може завищувати або недооцінювати минулий час. Існують навіть випадки, коли ваш комп'ютер, здавалося б, подорожує часом, оскільки минулий час буде негативним! (Наприклад, якщо годинник перемістився назад під час синхронізації.)
За словами Aria Haghighi у лекції "Розширене розпізнавання жестів iOS" курсу з курсу iOS 2013 в Stanford (34:00), вам слід скористатися, CACurrentMediaTime()
якщо вам потрібен точний часовий проміжок.
Завдання-C:
#import <QuartzCore/QuartzCore.h>
CFTimeInterval startTime = CACurrentMediaTime();
// perform some action
CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;
Швидкий:
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
це лише a double
, визначте NSDate
так:
typedef double NSTimeInterval;
Для всіх, хто приходить сюди, шукаючи реалізацію getTickCount () для iOS, ось моя після зведення різних джерел.
Раніше я мав помилку в цьому коді (я поділив його на 1000000 спочатку), що спричиняло певну кількісну оцінку результатів на моєму iPhone 6 (можливо, це не було проблемою на iPhone 4 / тощо, або я просто ніколи цього не помічав). Зауважте, що, не виконуючи цей поділ спочатку, існує певний ризик переповнення, якщо чисельник часової бази досить великий. Якщо хтось цікавий, тут є посилання з набагато більшою інформацією: https://stackoverflow.com/a/23378064/588476
З огляду на цю інформацію, можливо, безпечніше використовувати функцію Apple CACurrentMediaTime
!
Я також орієнтував mach_timebase_info
виклик, і він займає приблизно 19ns на моєму iPhone 6, тому я видалив (не потік) код, який кешував вихід цього виклику.
#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. на моєму 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.
* Caveat: Як уже згадували інші, використовуйте NSDate
для обчислення минулого часу лише для випадкових цілей. Однією з таких цілей може бути звичайне тестування, непрофільне профілювання, де потрібно просто грубе уявлення про те, як довго триває метод.
Ризик полягає в тому, що поточний час роботи пристрою може змінитися в будь-який момент через синхронізацію мережевих годин. Тож NSDate
час у будь-який момент міг стрибати вперед чи назад.
fabs(...)
для отримання абсолютного значення поплавця. Напр.NSTimeInterval timeInterval = fabs([start timeIntervalSinceNow]);