Saya perlu waktu antara dua peristiwa, misalnya, penampilan UIView dan reaksi pertama pengguna.
Bagaimana saya bisa mencapainya di Objective-C?
Saya perlu waktu antara dua peristiwa, misalnya, penampilan UIView dan reaksi pertama pengguna.
Bagaimana saya bisa mencapainya di Objective-C?
Jawaban:
NSDate *start = [NSDate date];
// do stuff...
NSTimeInterval timeInterval = [start timeIntervalSinceNow];
timeInterval
adalah perbedaan antara mulai dan sekarang, dalam hitungan detik, dengan presisi sub-milidetik.
[NSDate date]
dapat menyebabkan sulit untuk melacak bug, lihat jawaban ini untuk info lebih lanjut.
Anda tidak boleh mengandalkan [NSDate date]
untuk tujuan pengaturan waktu karena ini dapat membuat laporan yang berlebih atau kurang dilaporkan. Bahkan ada kasus di mana komputer Anda tampaknya akan melakukan perjalanan waktu karena waktu yang berlalu akan menjadi negatif! (Misalnya, jika jam bergerak mundur selama penghitungan waktu.)
Menurut Aria Haghighi dalam kuliah "Pengenalan Gerakan iOS Lanjutan" dari kursus Musim Dingin 2013 Stanford iOS (34:00), Anda harus menggunakan CACurrentMediaTime()
jika Anda membutuhkan interval waktu yang akurat.
Tujuan-C:
#import <QuartzCore/QuartzCore.h>
CFTimeInterval startTime = CACurrentMediaTime();
// perform some action
CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;
Cepat:
let startTime = CACurrentMediaTime()
// perform some action
let elapsedTime = CACurrentMediaTime() - startTime
Alasannya adalah [NSDate date]
sinkronisasi di server, sehingga dapat menyebabkan "cegukan sinkronisasi waktu" yang dapat menyebabkan bug yang sangat sulit dilacak. CACurrentMediaTime()
, di sisi lain, adalah waktu perangkat yang tidak berubah dengan sinkronisasi jaringan ini.
Anda akan perlu menambahkan pada kerangka QuartzCore untuk pengaturan target Anda.
[NSDate date]
dalam blok penyelesaian dalam blok pengiriman, saya mendapatkan waktu "saat ini" yang sama yang dilaporkan [NSDate date]
segera sebelum eksekusi mencapai titik di mana blok saya dibuat. CACurrentMediaTime()
memecahkan masalah ini.
CACurrentMediaTime()
berhenti berdetak bila perangkat memasuki mode sleep. Jika Anda menguji dengan perangkat terputus dari komputer, kunci, lalu tunggu ~ 10 menit Anda akan menemukan bahwa CACurrentMediaTime()
tidak sesuai dengan waktu jam dinding.
Gunakan timeIntervalSinceDate
metodenya
NSTimeInterval secondsElapsed = [secondDate timeIntervalSinceDate:firstDate];
NSTimeInterval
hanya a double
, definisikan NSDate
seperti ini:
typedef double NSTimeInterval;
Bagi siapa pun yang datang ke sini mencari implementasi getTickCount () untuk iOS, inilah milik saya setelah menyatukan berbagai sumber.
Sebelumnya saya memiliki bug dalam kode ini (saya dibagi dengan 10.00000 dulu) yang menyebabkan beberapa quantisation dari output pada iPhone 6 saya (mungkin ini bukan masalah pada iPhone 4 / etc atau saya hanya tidak pernah menyadarinya). Perhatikan bahwa dengan tidak melakukan pembagian itu terlebih dahulu, ada risiko overflow jika pembilang timebase cukup besar. Jika ada yang penasaran, ada tautan dengan informasi lebih lanjut di sini: https://stackoverflow.com/a/23378064/588476
Mengingat informasi itu, mungkin lebih aman menggunakan fungsi Apple CACurrentMediaTime
!
Saya juga melakukan benchmark pada mach_timebase_info
panggilan dan membutuhkan sekitar 19ns pada iPhone 6 saya, jadi saya menghapus kode (bukan threadsafe) yang merupakan caching output dari panggilan itu.
#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;
}
Berhati-hatilah dengan potensi risiko melimpah tergantung pada output panggilan timebase. Saya curiga (tetapi tidak tahu) bahwa itu mungkin konstan untuk setiap model iPhone. di iPhone 6 saya itu 125/3
.
Solusi yang digunakan CACurrentMediaTime()
cukup sepele:
uint64_t getTickCount(void)
{
double ret = CACurrentMediaTime();
return ret * 1000;
}
mach_timebase_info()
akan mengatur ulang pass-in mach_timebase_info_data_t
ke {0,0}
sebelum menyetelnya ke nilai aktual, yang dapat menyebabkan pembagian dengan nol jika kode dipanggil dari banyak utas. Gunakan dispatch_once()
sebagai gantinya (atau CACurrentMediaTime
yang hanya diubah waktu menjadi detik).
Untuk pengukuran waktu perkise (seperti GetTickCount), lihat juga mach_absolute_time dan Tanya Jawab Apple ini: http://developer.apple.com/qa/qa2004/qa1398.html .
gunakan fungsi timeIntervalSince1970 dari kelas NSDate seperti di bawah ini:
double start = [startDate timeIntervalSince1970];
double end = [endDate timeIntervalSince1970];
double difference = end - start;
pada dasarnya, inilah yang saya gunakan untuk membandingkan perbedaan dalam detik antara 2 tanggal yang berbeda. periksa juga tautan ini di sini
Jawaban lainnya benar (dengan peringatan *). Saya menambahkan jawaban ini hanya untuk menunjukkan contoh penggunaan:
- (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.
}
Di konsol debugger, Anda melihat sesuatu seperti ini:
DEBUG Method '-[XMAppDelegate getYourAffairsInOrder]' ran. Elapsed: 0.033827 seconds.
* Peringatan: Seperti yang disebutkan sebelumnya, gunakan NSDate
untuk menghitung waktu yang telah berlalu hanya untuk tujuan kasual. Salah satu tujuan tersebut mungkin pengujian umum, profil mentah, di mana Anda hanya ingin gambaran kasar tentang berapa lama suatu metode dibutuhkan.
Risikonya adalah bahwa pengaturan waktu jam perangkat saat ini dapat berubah setiap saat karena sinkronisasi jam jaringan. Sehingga NSDate
waktu bisa melompat maju atau mundur kapan saja.
fabs(...)
untuk mendapatkan nilai absolut float. Misalnya.NSTimeInterval timeInterval = fabs([start timeIntervalSinceNow]);