Objective-Cで経過時間を取得する


153

たとえば、UIViewの外観とユーザーの最初の反応など、2つのイベント間の経過時間を取得する必要があります。

Objective-Cでそれを実現するにはどうすればよいですか?

回答:


267
NSDate *start = [NSDate date];
// do stuff...
NSTimeInterval timeInterval = [start timeIntervalSinceNow];

timeInterval ミリ秒単位の精度での秒単位の開始と現在の差です。


18
fabs(...)floatの絶対値を取得するために使用できる@NicolasZozol 。例えば。NSTimeInterval timeInterval = fabs([start timeIntervalSinceNow]);
So Over It

1
timeIntervalの値が負のようです。
Jacky

負の値が得られた場合
--1を掛けれ

10
依存すると[NSDate date]、バグの追跡が困難になる可能性があります。詳細については、この回答を参照してください。
センスフル2013

@PinkFloydRocks —何ですか?どのようにして負の値が正当に発生しますか?
Todd Lehman

228

[NSDate date]経過時間を過大または過小報告する可能性があるため、タイミングの目的に依存しないでください。経過時間がマイナスになるので、コンピュータがタイムトラベルのように見える場合さえあります!(たとえば、タイミング中にクロックが逆方向に移動した場合)。

2013年冬のStanford iOSコース(34:00)の「高度なiOSジェスチャー認識」講義のAria HaghighiによるとCACurrentMediaTime()、正確な時間間隔が必要な場合は、これを使用する必要があります。

Objective-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フレームワークをターゲットの設定に。


17
これに賛成投票してください。私は誰もがNSDateがあなたの最初の選択肢であるべきであることに同意できると思いますが、この提案は私の問題を解決しました。[NSDate date]ディスパッチブロック内の完了ブロック内で呼び出すと、[NSDate date]実行が私のブロックが作成されたポイントに到達する直前に報告されていたのと同じ「現在の」時間を取得していました。CACurrentMediaTime()この問題を解決しました。
n00neimp0rtant 2014年

mm:ssのような表示に、elapsedTimeをどのように使用しますか?
Cyber​​Mew 2014

@Cyber​​Mew:それは別の問題です。iPhoneでNSTimeIntervalを年、月、日、時間、分、秒に分解する方法を参照してください一部のソリューション。
14

12
CACurrentMediaTime()デバイスがスリープ状態になると、がカチカチと止まることに注意してください。デバイスをコンピューターから切断してテストする場合は、ロックしてから10分ほど待つと、実CACurrentMediaTime()時間に追いつかないことがわかります。
russbishop 2015

#import <QuartzCore / QuartzCore.h>を追加してインポート
steveen zoleko

23

timeIntervalSinceDateメソッドを使用する

NSTimeInterval secondsElapsed = [secondDate timeIntervalSinceDate:firstDate];

NSTimeIntervalは単なるでありdouble、次のNSDateように定義します。

typedef double NSTimeInterval;

15

ここに来てiOSのgetTickCount()実装を探している人のために、さまざまなソースをまとめた後のものがここにあります。

以前、私はこのコードにバグがあり(最初に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のモデルごとに一定であるかもしれないと思います(しかし、わかりません)。私のiPhone 6でそれはだった125/3

使用するソリューションCACurrentMediaTime()は非常に簡単です:

uint64_t getTickCount(void)
{
    double ret = CACurrentMediaTime();
    return ret * 1000;
}

mach_timebase_info呼び出しに冗長な(void)キャストがある理由を誰かが知っていますか?
Simon Tillson、

@SimonTillsonそれは良い質問です-警告を消す必要があったか、またはどこかからそれをコピーして削除したことに気づかなかっただけです。思い出せない。
ウェインウロダ

2
これはスレッドセーフではありません。mach_timebase_info()渡されmach_timebase_info_data_t{0,0}値を実際の値に設定する前ににリセットします。これにより、コードが複数のスレッドから呼び出された場合にゼロ除算が発生する可能性があります。dispatch_once()代わりに使用してください(またはCACurrentMediaTime単にマッハ時間が秒に変換されます)。
wonder.mice

@ wonder.miceに感謝します。回答を更新しました(量子化に関する問題も見つかりました。6歳年下の私を責めます...)
Wayne Uroda


4

以下のようにNSDateクラスのtimeIntervalSince1970関数を使用します。

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

基本的に、これは2つの異なる日付間の秒単位の違いを比較するために使用するものです。また、このリンクをチェックし、ここで


0

他の答えは正解です(警告*付き)。この回答を追加して、使用例を示します。

- (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カジュアルな目的でのみ経過時間を計算するために使用します。そのような目的の1つは、一般的なテスト、大まかなプロファイリングであり、メソッドの所要時間のおおよその目安が必要な場合があります。

ネットワーククロックの同期により、デバイスのクロックの現在の時刻設定がいつでも変更される可能性があります。したがって、NSDate時間はいつでも前後にジャンプする可能性があります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.