Objective-C에서 경과 된 시간 얻기


155

예를 들어 UIView의 모양과 사용자의 첫 번째 반응과 같은 두 이벤트 사이에 경과 된 시간을 가져와야합니다.

Objective-C에서 어떻게 달성 할 수 있습니까?

답변:


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

timeInterval 밀리 초 미만의 정밀도로 시작과 지금의 차이 (초)입니다.


19
@NicolasZozol fabs(...)은 부동 소수점의 절대 값을 얻는 데 사용할 수 있습니다 . 예 : NSTimeInterval timeInterval = fabs([start timeIntervalSinceNow]);
그래서 이상이

1
timeInterval의 값이 음수 인 것 같습니다.
LiangWang

당신에게있는 거 좋은 곱셈과 -1 - 당신은 음의 값을 얻을 경우
PinkFloydRocks

10
의존하면 [NSDate date]버그를 추적하기가 어려울 수 있습니다 . 자세한 내용은 이 답변 을 참조하십시오.
Senseful

@PinkFloydRocks — 뭐? 음의 값이 합법적으로 어떻게 발생합니까?
토드 리먼

234

[NSDate date]경과 시간을 과도하거나 과소보고 할 수 있으므로 타이밍 목적 에 의존해서는 안됩니다 . 경과 시간이 음수이기 때문에 컴퓨터가 시간 여행을하는 것처럼 보이는 경우도 있습니다! (예 : 타이밍 중에 시계가 뒤로 이동 한 경우)

Winter 2013 Stanford iOS 과정 (34:00) 의 "Advanced iOS Gesture Recognition"강의에서 Aria Haghighi에 따르면 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 프레임 워크를 대상의 설정.


17
이것을 찬성하십시오. 모든 사람들이 NSDate가 첫 번째 옵션이어야한다는 데 동의 할 수 있다고 생각하지만이 제안은 내 문제를 해결했습니다. [NSDate date]디스패치 블록 내의 완료 블록 내에서 호출 할 때 [NSDate date]실행이 블록이 생성 된 지점에 도달하기 직전 에보고 된 것과 동일한 "현재"시간을 얻었습니다. CACurrentMediaTime()이 문제를 해결했습니다.
n00neimp0rtant 2014 년

mm : ss와 같은 디스플레이에 elapsedTime을 어떻게 사용합니까?
CyberMew 2014 년

@CyberMew : 그것은 별도의 문제입니다. iPhone에서 NSTimeInterval을 연도, 월, 일, 시간, 분 및 초로 나누는 방법을 참조하십시오 . 일부 솔루션.
Senseful

12
CACurrentMediaTime()장치가 절전 모드로 전환되면 틱 이 중지됩니다. 컴퓨터에서 분리 된 장치로 테스트하는 경우 잠그고 10 분 정도 기다리면 CACurrentMediaTime()벽시계 시간을 따라 가지 못하는 것을 알 수 있습니다.
russbishop 2015

추가 및 가져 오기 # import를 <QuartzCore / QuartzCore.h>
zoleko steveen

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에서 약 19ns가 걸리므로 해당 호출의 출력을 캐싱하는 (스레드 세이프가 아닌) 코드를 제거했습니다.

#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 호출에 중복 (무효) 캐스트가있는 이유를 아는 사람이 있습니까?
Simon Tillson 2010

@SimonTillson은 좋은 질문입니다. 경고를 무음으로 설정했거나 다른 곳에서 복사 한 후 삭제하는 것을 알지 못했습니다. 기억이 안나요.
Wayne Uroda

2
이것은 스레드로부터 안전하지 않습니다. mach_timebase_info()전달 된 값을 실제 값으로 설정 mach_timebase_info_data_t하기 {0,0}전에로 재설정하므로 여러 스레드에서 코드가 호출되면 0으로 나눌 수 있습니다. dispatch_once()대신 사용하십시오 (또는 CACurrentMediaTime마하 시간이 초로 변환 됨).
wonder.mice 18-06-23

감사합니다 @ wonder.mice, 저는 제 답변을 업데이트했습니다 (양자화에 관한 문제도 발견했습니다. 저는 6 살 어린 저를 비난합니다 ...)
Wayne Uroda 2018


4

아래와 같이 NSDate 클래스의 timeIntervalSince1970 함수를 사용하십시오.

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

기본적으로 이것은 두 개의 다른 날짜 사이의 초 차이를 비교하는 데 사용하는 것입니다. 여기 에서이 링크를 확인 하십시오.


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캐주얼 한 목적으로 만 경과 시간을 계산 하는 데 사용 합니다. 그러한 목적 중 하나는 일반적인 테스트, 조잡한 프로파일 링이 될 수 있습니다. 여기서는 메서드가 얼마나 오래 걸리는지 대략적인 아이디어를 원합니다.

위험은 네트워크 시계 동기화로 인해 장치의 시계의 현재 시간 설정이 언제든지 변경 될 수 있다는 것입니다. 따라서 NSDate시간은 언제든지 앞뒤로 이동할 수 있습니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.