J'ai besoin d'obtenir le temps écoulé entre deux événements, par exemple, l'apparition d'un UIView et la première réaction de l'utilisateur.
Comment puis-je y parvenir en Objective-C?
J'ai besoin d'obtenir le temps écoulé entre deux événements, par exemple, l'apparition d'un UIView et la première réaction de l'utilisateur.
Comment puis-je y parvenir en Objective-C?
Réponses:
NSDate *start = [NSDate date];
// do stuff...
NSTimeInterval timeInterval = [start timeIntervalSinceNow];
timeInterval
est la différence entre début et maintenant, en secondes, avec une précision inférieure à la milliseconde.
[NSDate date]
peut conduire à des bogues difficiles à suivre, voir cette réponse pour plus d'informations.
Vous ne devez pas vous en remettre à [NSDate date]
des fins de chronométrage car il peut sur-ou sous-déclarer le temps écoulé. Il y a même des cas où votre ordinateur va apparemment voyager dans le temps car le temps écoulé sera négatif! (Par exemple, si l'horloge a reculé pendant le chronométrage.)
Selon Aria Haghighi dans la conférence "Advanced iOS Gesture Recognition" du cours Winter 2013 Stanford iOS (34:00), vous devriez utiliser CACurrentMediaTime()
si vous avez besoin d'un intervalle de temps précis.
Objectif c:
#import <QuartzCore/QuartzCore.h>
CFTimeInterval startTime = CACurrentMediaTime();
// perform some action
CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;
Rapide:
let startTime = CACurrentMediaTime()
// perform some action
let elapsedTime = CACurrentMediaTime() - startTime
La raison en est que se [NSDate date]
synchronise sur le serveur, cela peut donc conduire à des «hoquets de synchronisation temporelle» qui peuvent conduire à des bogues très difficiles à suivre. CACurrentMediaTime()
, d'autre part, est une heure de l'appareil qui ne change pas avec ces synchronisations réseau.
Vous devrez ajouter le framework QuartzCore aux paramètres de votre cible.
[NSDate date]
intérieur d'un bloc d'achèvement dans un bloc de répartition, j'obtenais la même heure "actuelle" que celle signalée [NSDate date]
juste avant que l'exécution n'atteigne le point auquel mes blocs ont été créés. CACurrentMediaTime()
résolu ce problème.
CACurrentMediaTime()
cesse de clignoter lorsque l'appareil entre en veille. Si vous testez avec l'appareil déconnecté d'un ordinateur, verrouillez-le, puis attendez ~ 10 minutes, vous constaterez que CACurrentMediaTime()
cela ne correspond pas à l'heure de l'horloge murale.
Utilisez la timeIntervalSinceDate
méthode
NSTimeInterval secondsElapsed = [secondDate timeIntervalSinceDate:firstDate];
NSTimeInterval
est juste un double
, définissez NSDate
comme ceci:
typedef double NSTimeInterval;
Pour quiconque vient ici à la recherche d'une implémentation getTickCount () pour iOS, voici la mienne après avoir rassemblé diverses sources.
Auparavant, j'avais un bug dans ce code (je divisais d'abord par 1000000) qui provoquait une quantification de la sortie sur mon iPhone 6 (peut-être que ce n'était pas un problème sur iPhone 4 / etc ou je ne l'ai tout simplement jamais remarqué). Notez qu'en n'effectuant pas cette division en premier, il y a un risque de débordement si le numérateur de la base de temps est assez grand. Si quelqu'un est curieux, il y a un lien avec beaucoup plus d'informations ici: https://stackoverflow.com/a/23378064/588476
À la lumière de ces informations, il est peut-être plus sûr d'utiliser la fonction Apple CACurrentMediaTime
!
J'ai également évalué l' mach_timebase_info
appel et cela prend environ 19ns sur mon iPhone 6, j'ai donc supprimé le code (non threadsafe) qui mettait en cache la sortie de cet appel.
#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;
}
Soyez conscient du risque potentiel de dépassement de capacité en fonction de la sortie de l'appel de base de temps. Je soupçonne (mais je ne sais pas) que cela pourrait être une constante pour chaque modèle d'iPhone. sur mon iPhone 6 c'était 125/3
.
La solution à l'aide CACurrentMediaTime()
est assez triviale:
uint64_t getTickCount(void)
{
double ret = CACurrentMediaTime();
return ret * 1000;
}
mach_timebase_info()
réinitialisera passé mach_timebase_info_data_t
à {0,0}
avant de le définir sur les valeurs réelles, ce qui peut entraîner une division par zéro si le code est appelé à partir de plusieurs threads. Utilisez à la dispatch_once()
place (ou CACurrentMediaTime
qui est juste le temps mach converti en secondes).
Pour les mesures de temps de précision (comme GetTickCount), jetez également un œil à mach_absolute_time et à ce Q&R Apple: http://developer.apple.com/qa/qa2004/qa1398.html .
utilisez la fonction timeIntervalSince1970 de la classe NSDate comme ci-dessous:
double start = [startDate timeIntervalSince1970];
double end = [endDate timeIntervalSince1970];
double difference = end - start;
en gros, c'est ce que j'utilise pour comparer la différence en secondes entre 2 dates différentes. vérifiez également ce lien ici
Les autres réponses sont correctes (avec une mise en garde *). J'ajoute cette réponse simplement pour montrer un exemple d'utilisation:
- (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.
}
Sur la console du débogueur, vous voyez quelque chose comme ceci:
DEBUG Method '-[XMAppDelegate getYourAffairsInOrder]' ran. Elapsed: 0.033827 seconds.
* Avertissement: comme d'autres l'ont mentionné, utilisez NSDate
pour calculer le temps écoulé uniquement à des fins occasionnelles. L'un de ces objectifs pourrait être des tests courants, un profilage brut, où vous voulez juste avoir une idée approximative de la durée d'une méthode.
Le risque est que le réglage de l'heure actuelle de l'horloge de l'appareil puisse changer à tout moment en raison de la synchronisation de l'horloge du réseau. Le NSDate
temps pouvait donc avancer ou reculer à tout moment.
fabs(...)
pour obtenir la valeur absolue d'un flottant. Par exemple.NSTimeInterval timeInterval = fabs([start timeIntervalSinceNow]);