Objective-C'de geçen süreyi alma


153

İki olay arasında geçen süreyi almam gerekiyor, örneğin bir UIView görünümü ve kullanıcının ilk tepkisi.

Objective-C ile nasıl başarabilirim?

Yanıtlar:


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

timeInterval milisaniye altı hassasiyetle başlangıç ​​ve şimdi arasındaki farkın saniye cinsinden farkıdır.


18
@NicolasZozol fabs(...)bir şamandıranın mutlak değerini elde etmek için kullanabilirsiniz . Örneğin. NSTimeInterval timeInterval = fabs([start timeIntervalSinceNow]);
Yani Üzeri O

1
timeInterval değeri negatif görünüyor.
Jacky

negatif bir değer alırsanız - -1 ile çarpın ve iyisiniz
PinkFloydRocks

10
Güvenmek [NSDate date]hataları izlemek zor olabilir, daha fazla bilgi için bu cevaba bakınız .
Senseful

@PinkFloydRocks - Ne? Negatif bir değer meşru olarak nasıl ortaya çıkabilir?
Todd Lehman

228

[NSDate date]Geçen zamanı gereğinden fazla veya az rapor edebileceğinden, zamanlama amaçları için güvenmemelisiniz . Hatta geçen zaman negatif olacağından bilgisayarınızın görünüşte zaman yolculuğu olacağı durumlar bile var! (Örneğin, zamanlama sırasında saat geriye doğru hareket ederse.)

Winter 2013 Stanford iOS kursunun (34:00) "Gelişmiş iOS Hareket Tanıma" dersindeki Aria Haghighi'ye göre, CACurrentMediaTime()doğru bir zaman aralığına ihtiyacınız varsa kullanmalısınız .

Objective-C:

#import <QuartzCore/QuartzCore.h>
CFTimeInterval startTime = CACurrentMediaTime();
// perform some action
CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;

Swift:

let startTime = CACurrentMediaTime()
// perform some action
let elapsedTime = CACurrentMediaTime() - startTime

Bunun nedeni [NSDate date]sunucuda senkronize edilmesidir, bu nedenle izlenmesi çok zor hatalara yol açabilecek "zaman senkronizasyonu hıçkırıklarına" yol açabilir. CACurrentMediaTime()diğer yandan, bu ağ senkronizasyonlarıyla değişmeyen bir cihaz süresidir.

Sen gerekecektir eklemek QuartzCore çerçevesini Hedefinizin ayarlarına.


17
Lütfen bunu oylayın. Herkesin NSDate'in ilk seçeneğiniz olması gerektiği konusunda hemfikir olabileceğini düşünsem de bu öneri benim sorunumu çözdü. Bir [NSDate date]dağıtım bloğu içindeki bir tamamlama bloğunu çağırırken , [NSDate date]yürütme bloklarımın oluşturulduğu noktaya gelmeden hemen önce bildirilen aynı "şimdiki" zamanı alıyordum . CACurrentMediaTime()bu sorunu çözdü.
n00neimp0rtant

ElapsedTime öğesini mm: ss gibi ekranlar için nasıl kullanırız?
CyberMew


12
Unutmayın CACurrentMediaTime()cihaz uyku girdiğinde geçiyor durur. Cihazın bilgisayar bağlantısı kesilmiş durumdayken test ederseniz, kilitleyin, sonra CACurrentMediaTime()duvar saatine uymadığını ~ 10 dakika bekleyin .
russbishop

ekleme ve içe aktarma #import <QuartzCore / QuartzCore.h>
steveen zoleko

23

timeIntervalSinceDateYöntemi kullanın

NSTimeInterval secondsElapsed = [secondDate timeIntervalSinceDate:firstDate];

NSTimeIntervalsadece bir double, şöyle tanımlayın NSDate:

typedef double NSTimeInterval;

15

Buraya iOS için getTickCount () uygulaması arayan herkes için, çeşitli kaynakları bir araya getirdikten sonra benimdir.

Daha önce bu kodda bir hata vardı (ilk önce 1000000'e böldüm) ki bu benim iPhone 6'da çıkışın bir miktar miktarına neden oldu (belki de bu iPhone 4 / etc'de bir sorun değildi ya da hiç fark etmedim). İlk önce bu bölümü gerçekleştirmeyerek, zaman tabanının payı oldukça büyükse taşma riski olduğunu unutmayın. Merak eden biri varsa, burada daha fazla bilgi içeren bir bağlantı var: https://stackoverflow.com/a/23378064/588476

Bu bilgiler ışığında belki Apple'ın işlevini kullanmak daha güvenlidir CACurrentMediaTime !

Ayrıca mach_timebase_infoaramayı kıyasladım ve iPhone 6'ımda yaklaşık 19ns sürüyor, bu yüzden bu aramanın çıkışını önbelleğe alan (threadsafe değil) kodunu kaldırdım.

#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;
}

Zaman tabanı çağrısının çıkışına bağlı olarak olası taşma riskinin farkında olun. İPhone'un her modeli için sabit olabileceğinden şüpheleniyorum (ama bilmiyorum). iPhone 6'mda öyleydi 125/3.

Kullanarak çözüm CACurrentMediaTime()oldukça önemsiz:

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

Mach_timebase_info çağrısında neden gereksiz (geçersiz) bir döküm olduğunu bilen var mı?
Simon Tillson

@SimonTillson bu iyi bir soru - ya bir uyarıyı susturmak gerekiyordu ya da başka bir yerden kopyaladım ve silmeyi fark etmedim. Hatırlayamıyorum.
Wayne Uroda

2
Bu iş parçacığı için güvenli değildir. mach_timebase_info()geçirildi, tekrar ayarlanır mach_timebase_info_data_tiçin {0,0}kod birden çok iş parçacığı denir eğer sıfıra bölme neden olabilir gerçek değerleri, bunu ayarlamadan önce. dispatch_once()Bunun yerine kullanın (veya CACurrentMediaTimeyalnızca saniyeye dönüştürülen mach süresi).
wonder.mice

Teşekkürler @ wonder.mice, cevabımı güncelledim (nicemleme ile ilgili bir sorun da buldum, 6 yaşındaki genç beni suçluyorum ...)
Wayne Uroda


4

NSDate sınıfının timeIntervalSince1970 işlevini aşağıdaki gibi kullanın:

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

temelde, ben 2 farklı tarih arasındaki saniye farkı karşılaştırmak için kullandığım budur. ayrıca bu bağlantıyı buradan kontrol edin


0

Diğer cevaplar doğrudur (bir uyarı ile *). Bu cevabı basitçe örnek bir kullanım göstermek için ekliyorum:

- (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.
}

Hata ayıklayıcı konsolunda şöyle bir şey görürsünüz:

DEBUG Method '-[XMAppDelegate getYourAffairsInOrder]' ran. Elapsed: 0.033827 seconds.

* Uyarı: Diğerleri de belirtildiği gibi, NSDategeçen zamanı sadece gündelik amaçlar için hesaplamak için kullanın . Böyle bir amaç, bir yöntemin ne kadar sürdüğü hakkında kabaca bir fikir edinmek istediğiniz ortak testler, ham profil oluşturma olabilir.

Risk, ağ saati senkronizasyonu nedeniyle cihazın saatinin geçerli saat ayarının her an değişebilmesidir. Böylece NSDatezaman her an ileri veya geri atlayabilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.