非常に正確に時間を取得する簡単な方法はありますか?
メソッド呼び出し間の遅延を計算する必要があります。具体的には、UIScrollViewでのスクロール速度を計算します。
mach_absolute_time()
を使用して、正確な測定値を取得できます。
http://developer.Apple.com/qa/qa2004/qa1398.html を参照してください
CACurrentMediaTime()
も利用できます。これは基本的に同じものですが、使いやすいインターフェースを備えています。
経過時間の測定にNSDate
、CFAbsoluteTimeGetCurrent
、またはgettimeofday
を使用しないでください。これらはすべてシステムクロックに依存します。システムクロックは、ネットワーク時刻同期(NTP)がクロックを更新する(ドリフトを調整することが多い)、DST調整など、さまざまな理由によりany時間で変更される可能性があります。うるう秒など。
これは、ダウンロードまたはアップロードの速度を測定している場合、実際の出来事とは関係のない突然の急増または急落が発生することを意味します。パフォーマンステストには、奇妙で不正確な外れ値が含まれます。手動タイマーは、不適切な期間の後にトリガーされます。時間は逆戻りすることさえあり、負のデルタになり、無限再帰またはデッドコードになります(はい、私はこれらの両方を行いました)。
つかいます mach_absolute_time
。カーネルがブートされてからの実際の秒数を測定します。単調に増加し(逆戻りすることはありません)、日付と時刻の設定の影響を受けません。苦労するので、NSTimeInterval
sを提供する簡単なラッパーを次に示します。
// LBClock.h
@interface LBClock : NSObject
+ (instancetype)sharedClock;
// since device boot or something. Monotonically increasing, unaffected by date and time settings
- (NSTimeInterval)absoluteTime;
- (NSTimeInterval)machAbsoluteToTimeInterval:(uint64_t)machAbsolute;
@end
// LBClock.m
#include <mach/mach.h>
#include <mach/mach_time.h>
@implementation LBClock
{
mach_timebase_info_data_t _clock_timebase;
}
+ (instancetype)sharedClock
{
static LBClock *g;
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
g = [LBClock new];
});
return g;
}
- (id)init
{
if(!(self = [super init]))
return nil;
mach_timebase_info(&_clock_timebase);
return self;
}
- (NSTimeInterval)machAbsoluteToTimeInterval:(uint64_t)machAbsolute
{
uint64_t nanos = (machAbsolute * _clock_timebase.numer) / _clock_timebase.denom;
return nanos/1.0e9;
}
- (NSTimeInterval)absoluteTime
{
uint64_t machtime = mach_absolute_time();
return [self machAbsoluteToTimeInterval:machtime];
}
@end
CFAbsoluteTimeGetCurrent()
は絶対時間をdouble
値として返しますが、その精度がわからない-it mightは数十ミリ秒ごとに更新するだけです。または、マイクロ秒ごとに更新するかもしれません。
mach_absolute_time()
は使用しません。これは、ティックを使用して絶対時間(おそらくアップタイム)でカーネルとプロセッサの組み合わせを照会するためです。
私が使用するもの:
_CFAbsoluteTimeGetCurrent();
_
この機能は、iOSとOSXのソフトウェアとハードウェアの違いを修正するために最適化されています。
Something Geekier
mach_absolute_time()
とAFAbsoluteTimeGetCurrent()
の差の商は常に約24000011.154871です。
ここに私のアプリのログがあります:
最終結果時間はCFAbsoluteTimeGetCurrent()
'sの違いであることに注意してください
_ 2012-03-19 21:46:35.609 Rest Counter[3776:707] First Time: 353900795.609040
2012-03-19 21:46:36.360 Rest Counter[3776:707] Second Time: 353900796.360177
2012-03-19 21:46:36.361 Rest Counter[3776:707] Final Result Time (difference): 0.751137
2012-03-19 21:46:36.363 Rest Counter[3776:707] Mach absolute time: 18027372
2012-03-19 21:46:36.365 Rest Counter[3776:707] Mach absolute time/final time: 24000113.153295
2012-03-19 21:46:36.367 Rest Counter[3776:707] -----------------------------------------------------
2012-03-19 21:46:43.074 Rest Counter[3776:707] First Time: 353900803.074637
2012-03-19 21:46:43.170 Rest Counter[3776:707] Second Time: 353900803.170256
2012-03-19 21:46:43.172 Rest Counter[3776:707] Final Result Time (difference): 0.095619
2012-03-19 21:46:43.173 Rest Counter[3776:707] Mach absolute time: 2294833
2012-03-19 21:46:43.175 Rest Counter[3776:707] Mach absolute time/final time: 23999753.727777
2012-03-19 21:46:43.177 Rest Counter[3776:707] -----------------------------------------------------
2012-03-19 21:46:46.499 Rest Counter[3776:707] First Time: 353900806.499199
2012-03-19 21:46:55.017 Rest Counter[3776:707] Second Time: 353900815.016985
2012-03-19 21:46:55.018 Rest Counter[3776:707] Final Result Time (difference): 8.517786
2012-03-19 21:46:55.020 Rest Counter[3776:707] Mach absolute time: 204426836
2012-03-19 21:46:55.022 Rest Counter[3776:707] Mach absolute time/final time: 23999996.639500
2012-03-19 21:46:55.024 Rest Counter[3776:707] -----------------------------------------------------
_
#define CTTimeStart() NSDate * __date = [NSDate date]
#define CTTimeEnd(MSG) NSLog(MSG " %g",[__date timeIntervalSinceNow]*-1)
使用法:
CTTimeStart();
...
CTTimeEnd(@"that was a long time:");
出力:
2013-08-23 15:34:39.558 App-Dev[21229:907] that was a long time: .0023
また、Unixエポックで初期化された64ビットNSNumber
をミリ秒単位で計算する方法もここにあります。それがCoreDataでの格納方法です。この方法で日付を保存するシステムとやり取りするアプリにこれが必要でした。
+ (NSNumber*) longUnixEpoch {
return [NSNumber numberWithLongLong:[[NSDate date] timeIntervalSince1970] * 1000];
}
_mach_absolute_time
_に基づく関数は、短い測定に適しています。
ただし、長時間の測定では、デバイスがスリープしている間はカチカチ音がしないという重要な注意事項があります。
起動後の時間を取得する機能があります。寝ている間も止まりません。また、gettimeofday
は単調ではありませんが、私の実験では、システム時間が変わるとブート時間が変わることが常にあるので、うまく動作するはずです。
_func timeSinceBoot() -> TimeInterval
{
var bootTime = timeval()
var currentTime = timeval()
var timeZone = timezone()
let mib = UnsafeMutablePointer<Int32>.allocate(capacity: 2)
mib[0] = CTL_KERN
mib[1] = KERN_BOOTTIME
var size = MemoryLayout.size(ofValue: bootTime)
var timeSinceBoot = 0.0
gettimeofday(¤tTime, &timeZone)
if sysctl(mib, 2, &bootTime, &size, nil, 0) != -1 && bootTime.tv_sec != 0 {
timeSinceBoot = Double(currentTime.tv_sec - bootTime.tv_sec)
timeSinceBoot += Double(currentTime.tv_usec - bootTime.tv_usec) / 1000000.0
}
return timeSinceBoot
}
_
また、iOS 10およびmacOS 10.12以降では、CLOCK_MONOTONICを使用できます。
_if #available(OSX 10.12, *) {
var uptime = timespec()
if clock_gettime(CLOCK_MONOTONIC_RAW, &uptime) == 0 {
return Double(uptime.tv_sec) + Double(uptime.tv_nsec) / 1000000000.0
}
}
_
まとめると:
Date.timeIntervalSinceReferenceDate
_ —単調ではなく、システム時間の変更時に変更CFAbsoluteTimeGetCurrent()
—単調ではなく、後方に進む可能性がありますCACurrentMediaTime()
—デバイスがスリープ状態になるとカチカチ音をたてなくなりますtimeSinceBoot()
—スリープしませんが、単調ではない場合がありますCLOCK_MONOTONIC
_ —スリープせず、単調で、iOS 10以降でサポートされていますNSDateを使用すると、1970年1月1日から現在の時刻をミリ秒単位で取得できます。
- (double)currentTimeInMilliseconds {
NSDate *date = [NSDate date];
return [date timeIntervalSince1970]*1000;
}
私はこれが古いものであることを知っていますが、私はそれをもう一度通り過ぎてさまよいました。
最善の策は、これに関する私のブログ投稿をチェックすることです: Objective-Cのタイミング:ストップウォッチ
基本的に、非常に基本的な方法で視聴を停止するクラスを作成しましたが、カプセル化されているため、次の操作を行うだけで済みます。
[MMStopwatchARC start:@"My Timer"];
// your work here ...
[MMStopwatchARC stop:@"My Timer"];
そして、次のようになります。
MyApp[4090:15203] -> Stopwatch: [My Timer] runtime: [0.029]
ログに...
もう一度、もう少し私の投稿をチェックするか、ここからダウンロードしてください: MMStopwatch.Zip