매우 정확하게 시간을 얻는 쉬운 방법이 있습니까?
메서드 호출 간의 지연을 계산해야합니다. 보다 구체적으로 UIScrollView에서 스크롤 속도를 계산하고 싶습니다.
매우 정확하게 시간을 얻는 쉬운 방법이 있습니까?
메서드 호출 간의 지연을 계산해야합니다. 보다 구체적으로 UIScrollView에서 스크롤 속도를 계산하고 싶습니다.
답변:
NSDate
그리고 timeIntervalSince*
메소드는 반환 NSTimeInterval
밀리 초 이하의 정확도로 이중 인을. NSTimeInterval
초 단위이지만 더 큰 정밀도를 제공하기 위해 double을 사용합니다.
밀리 초 시간 정확도를 계산하기 위해 다음을 수행 할 수 있습니다.
// Get a current time for where you want to start measuring from
NSDate *date = [NSDate date];
// do work...
// Find elapsed time and convert to milliseconds
// Use (-) modifier to conversion since receiver is earlier than now
double timePassed_ms = [date timeIntervalSinceNow] * -1000.0;
을 사용하여이 간격을 계산하는 다른 많은 방법이 있으며 NSDate Class ReferenceNSDate
에있는 클래스 문서를 참조 NSDate
하는 것이 좋습니다 .
NSDate
했고 mach_absolute_time()
약 30ms 수준에서. 27 vs. 29, 36 vs. 39, 43 vs. 45. NSDate
는 사용하기 쉬웠고 결과는 신경 쓰지 않을 정도로 비슷했습니다.
mach_absolute_time()
정확한 측정을 위해 사용할 수 있습니다.
참조 http://developer.apple.com/qa/qa2004/qa1398.html를
또한 볼 수 있습니다 CACurrentMediaTime()
본질적으로 같은 일을하지만, 사용하기 쉬운 인터페이스이다.
(참고 :이 답변은 2009 년에 작성되었습니다. clock_gettime()
최신 버전의 macOS 및 iOS에서 사용할 수있는 더 간단한 POSIX 인터페이스에 대한 Pavel Alexeev의 답변을 참조하십시오 .)
CACurrentMediaTime()
그 변환 mach_absolute_time()
직접적으로 double
.
elapsedNano
유형 인 Nanoseconds
일반 정수 유형하지 않은. UnsignedWide
두 개의 32 비트 정수 필드가있는 구조체 인의 별칭입니다 . 원하는 UnsignedWideToUInt64()
경우 캐스트 대신 사용할 수 있습니다 .
사용하지 마십시오 NSDate
, CFAbsoluteTimeGetCurrent
또는 gettimeofday
경과 시간을 측정 할 수 있습니다. 이들은 모두 시스템 시계에 의존하며, 이는 네트워크 시간 동기화 (NTP) 시계 업데이트 (드리프트를 조정하기 위해 자주 발생 함), DST 조정, 윤초 등과 같은 다양한 이유로 인해 언제든지 변경 될 수 있습니다 .
즉, 다운로드 또는 업로드 속도를 측정하는 경우 실제로 발생한 일과 관련이없는 수치가 갑자기 급증하거나 감소하게됩니다. 성능 테스트에는 이상하게 잘못된 이상 값이 있습니다. 잘못된 기간이 지나면 수동 타이머가 트리거됩니다. 시간은 뒤로 갈 수도 있고 음의 델타로 끝날 수 있으며 무한 재귀 또는 데드 코드로 끝날 수 있습니다 (예,이 두 가지를 모두 수행했습니다).
사용 mach_absolute_time
. 커널이 부팅 된 이후의 실제 시간을 측정합니다. 단조롭게 증가하며 (뒤로 이동하지 않음) 날짜 및 시간 설정의 영향을받지 않습니다. 작업하는 것이 고통스럽기 때문에 다음을 제공하는 간단한 래퍼가 있습니다 NSTimeInterval
.
// 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
CACurrentMediaTime()
QuartzCore에서?
@import Darwin;
대신 사용할 수도 있습니다#include <mach/mach_time.h>
CFAbsoluteTimeGetCurrent()
A와 절대 시간 반환 double
값을,하지만 난 정밀도가 무엇인지 모르는 -이 있습니다 매 수십 밀리 초를 업데이트하거나 모든 마이크로를, 나도 몰라 업데이트 할 수 있습니다.
72.89674947369
초 값은 다른 모든 값을 고려할 때 매우 드물다고 말해야 할 것입니다. ;)
mach_absolute_time()
틱 (아마 가동 시간)을 사용하여 절대 시간 동안 커널과 프로세서의 조합을 쿼리 하기 때문에 사용하지 않을 것입니다.
내가 사용하는 것 :
CFAbsoluteTimeGetCurrent();
이 기능은 iOS 및 OSX 소프트웨어 및 하드웨어의 차이를 수정하도록 최적화되어 있습니다.
더 괴짜
차이의 지수 mach_absolute_time()
와는 AFAbsoluteTimeGetCurrent()
항상 주위 24000011.154871입니다
다음은 내 앱의 로그입니다.
최종 결과 시간에 차이가 있음을하시기 바랍니다 노트 CFAbsoluteTimeGetCurrent()
의이
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] -----------------------------------------------------
mach_absolute_time()
a mach_timebase_info_data
와 함께 사용 을 끝내고 (long double)((mach_absolute_time()*time_base.numer)/((1000*1000)*time_base.denom));
. 마하 타임베이스를 얻으려면 할 수 있습니다(void)mach_timebase_info(&your_timebase);
#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
NSDate
언제든지 변경 될 수있는 시스템 시계에 의존하여 잠재적으로 잘못된 시간 간격 또는 음의 시간 간격이 발생할 수 있습니다. mach_absolute_time
대신 정확한 경과 시간을 얻으려면 사용하십시오 .
mach_absolute_time
기기 재부팅의 영향을받을 수 있습니다. 대신 서버 시간을 사용하십시오.
기반 기능 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부터 지원됨이게 낡은 거라는 건 알지만 다시 지나가는 나 자신을 발견했기 때문에 여기에 내 옵션을 제출할 것이라고 생각했습니다.
가장 좋은 방법은 내 블로그 게시물을 확인하는 것입니다. Objective-C : A stopwatch의 Timing things
기본적으로 저는 매우 기본적인 방식으로 시청을 중단하지만 캡슐화되어 다음 작업 만 수행하면되는 클래스를 작성했습니다.
[MMStopwatchARC start:@"My Timer"];
// your work here ...
[MMStopwatchARC stop:@"My Timer"];
그리고 결국 :
MyApp[4090:15203] -> Stopwatch: [My Timer] runtime: [0.029]
로그에 ...
다시 한 번, 내 게시물을 좀 더 확인하거나 여기에서 다운로드하십시오 : MMStopwatch.zip
NSDate
언제든지 변경 될 수있는 시스템 시계에 의존하여 잠재적으로 잘못된 시간 간격 또는 음의 시간 간격이 발생할 수 있습니다. mach_absolute_time
대신 정확한 경과 시간을 얻으려면 사용하십시오 .
이를 위해 @Jeff Thompson의 답변의 Swift 버전이 필요합니다.
// Get a current time for where you want to start measuring from
var date = NSDate()
// do work...
// Find elapsed time and convert to milliseconds
// Use (-) modifier to conversion since receiver is earlier than now
var timePassed_ms: Double = date.timeIntervalSinceNow * -1000.0
도움이 되었기를 바랍니다.
NSDate
언제든지 변경 될 수있는 시스템 시계에 의존하여 잠재적으로 잘못된 시간 간격 또는 음의 시간 간격이 발생할 수 있습니다. mach_absolute_time
대신 정확한 경과 시간을 얻으려면 사용하십시오 .