ฉันต้องการให้เวลาผ่านไประหว่างสองเหตุการณ์ตัวอย่างเช่นการปรากฏตัวของ UIView และปฏิกิริยาแรกของผู้ใช้
ฉันจะทำให้สำเร็จใน Objective-C ได้อย่างไร
ฉันต้องการให้เวลาผ่านไประหว่างสองเหตุการณ์ตัวอย่างเช่นการปรากฏตัวของ UIView และปฏิกิริยาแรกของผู้ใช้
ฉันจะทำให้สำเร็จใน Objective-C ได้อย่างไร
คำตอบ:
NSDate *start = [NSDate date];
// do stuff...
NSTimeInterval timeInterval = [start timeIntervalSinceNow];
timeInterval
ความแตกต่างระหว่างการเริ่มต้นและตอนนี้ในไม่กี่วินาทีที่มีความแม่นยำเป็นมิลลิวินาที
คุณไม่ควรใช้[NSDate date]
เพื่อจุดประสงค์ในการจับเวลาเนื่องจากอาจมีเวลามากหรือน้อยเกินไปในการรายงานเวลาที่ผ่านไป มีบางครั้งที่คอมพิวเตอร์ของคุณอาจต้องเดินทางข้ามเวลาเนื่องจากเวลาที่ผ่านไปจะเป็นค่าลบ! (เช่นถ้านาฬิกาเดินถอยหลังในช่วงเวลา)
ตาม Aria Haghighi ในการบรรยาย "Advanced iOS Gesture Recognition" ของหลักสูตร Winter 2013 Stanford iOS (34:00) คุณควรใช้CACurrentMediaTime()
หากคุณต้องการช่วงเวลาที่แม่นยำ
Objective-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]
ซิงค์บนเซิร์ฟเวอร์ดังนั้นจึงอาจนำไปสู่ "hiccups การซิงค์เวลา" ซึ่งอาจทำให้เกิดข้อบกพร่องที่ติดตามได้ยากมาก CACurrentMediaTime()
ในทางกลับกันเวลาของอุปกรณ์ที่ไม่เปลี่ยนแปลงด้วยการซิงค์เครือข่ายเหล่านี้
คุณจะต้องเพิ่มกรอบ QuartzCoreการตั้งค่าเป้าหมายของคุณ
[NSDate date]
ภายในบล็อกที่เสร็จสมบูรณ์ภายในบล็อกการจัดส่งฉันได้รับเวลา "ปัจจุบัน" ที่เหมือนกันซึ่งถูกรายงานโดย[NSDate date]
ทันทีก่อนที่การดำเนินการจะเข้าสู่จุดที่บล็อกของฉันถูกสร้าง CACurrentMediaTime()
แก้ไขปัญหานี้
CACurrentMediaTime()
จะหยุดฟ้องเมื่ออุปกรณ์เข้าสู่โหมดสลีป หากคุณทดสอบว่าอุปกรณ์ถูกตัดการเชื่อมต่อจากคอมพิวเตอร์ให้ล็อกแล้วรอประมาณ 10 นาทีคุณจะพบว่าไม่ได้CACurrentMediaTime()
ตามเวลานาฬิกาปลุก
ใช้timeIntervalSinceDate
วิธีการ
NSTimeInterval secondsElapsed = [secondDate timeIntervalSinceDate:firstDate];
NSTimeInterval
เป็นเพียงdouble
, ให้นิยามNSDate
ดังนี้:
typedef double NSTimeInterval;
สำหรับใครก็ตามที่มาที่นี่เพื่อมองหาการใช้งาน getTickCount () สำหรับ iOS นี่คือสิ่งที่ฉันทำหลังจากรวบรวมแหล่งต่าง ๆ เข้าด้วยกัน
ก่อนหน้านี้ฉันมีข้อผิดพลาดในรหัสนี้ (ฉันหารด้วย 1000000 ก่อน) ซึ่งเป็นสาเหตุของปริมาณการส่งออกของ iPhone 6 ของฉัน (บางทีนี่อาจไม่ใช่ปัญหาใน iPhone 4 / ฯลฯ หรือฉันไม่เคยสังเกตเลย) โปรดทราบว่าการไม่ทำการแบ่งส่วนนั้นก่อนมีความเสี่ยงที่จะเกิดการล้นหากตัวเศษของฐานเวลามีขนาดค่อนข้างใหญ่ หากใครอยากรู้อยากเห็นมีลิงค์พร้อมข้อมูลเพิ่มเติมอีกมากมายที่นี่: https://stackoverflow.com/a/23378064/588476
จากข้อมูลดังกล่าวอาจจะปลอดภัยกว่าที่จะใช้ฟังก์ชั่นของ Apple CACurrentMediaTime
!
ฉันยังทำการเปรียบเทียบการmach_timebase_info
โทรและใช้เวลาประมาณ 19ns บน iPhone 6 ของฉันดังนั้นฉันจึงลบรหัส (ไม่ใช่ threadsafe) ซึ่งแคชการแสดงผลของการโทรนั้น
#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()
จะรีเซ็ตรหัสผ่านmach_timebase_info_data_t
เป็น{0,0}
ก่อนที่จะตั้งค่าเป็นค่าจริงซึ่งอาจทำให้เกิดการหารด้วยศูนย์หากรหัสถูกเรียกจากหลายเธรด ใช้dispatch_once()
แทน (หรือCACurrentMediaTime
ซึ่งเป็นเพียงเวลา mach ปรับเป็นวินาที)
ใช้ฟังก์ชัน timeIntervalSince1970 ของคลาส NSDate ดังนี้:
double start = [startDate timeIntervalSince1970];
double end = [endDate timeIntervalSince1970];
double difference = end - start;
นี่คือสิ่งที่ฉันใช้เพื่อเปรียบเทียบความแตกต่างในไม่กี่วินาทีระหว่าง 2 วันที่แตกต่างกัน ตรวจสอบลิงค์นี้ที่นี่
คำตอบอื่น ๆ นั้นถูกต้อง (มีข้อแม้ *) ฉันเพิ่มคำตอบนี้เพื่อแสดงตัวอย่างการใช้งาน:
- (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.
* Caveat: ตามที่คนอื่นพูดถึงให้ใช้ NSDate
ในการคำนวณเวลาที่ผ่านไปเพื่อวัตถุประสงค์ชั่วคราวเท่านั้น หนึ่งในวัตถุประสงค์ดังกล่าวอาจเป็นการทดสอบทั่วไปการทำโปรไฟล์อย่างหยาบซึ่งคุณเพียงต้องการทราบวิธีการที่ใช้
ความเสี่ยงคือการตั้งค่าเวลาปัจจุบันของนาฬิกาอุปกรณ์สามารถเปลี่ยนแปลงได้ทุกเมื่อเนื่องจากการซิงค์สัญญาณเครือข่าย ดังนั้นNSDate
เวลาสามารถกระโดดไปข้างหน้าหรือข้างหลังในเวลาใดก็ได้
fabs(...)
เพื่อรับค่าสัมบูรณ์ของทุ่น เช่น.NSTimeInterval timeInterval = fabs([start timeIntervalSinceNow]);