Tôi cần phải có thời gian trôi qua giữa hai sự kiện, ví dụ, sự xuất hiện của một UIView và phản ứng đầu tiên của người dùng.
Làm thế nào tôi có thể đạt được nó trong Objective-C?
Tôi cần phải có thời gian trôi qua giữa hai sự kiện, ví dụ, sự xuất hiện của một UIView và phản ứng đầu tiên của người dùng.
Làm thế nào tôi có thể đạt được nó trong Objective-C?
Câu trả lời:
NSDate *start = [NSDate date];
// do stuff...
NSTimeInterval timeInterval = [start timeIntervalSinceNow];
timeInterval
là sự khác biệt giữa bắt đầu và bây giờ, tính bằng giây, với độ chính xác dưới một phần nghìn giây.
[NSDate date]
có thể dẫn đến khó theo dõi lỗi, xem câu trả lời này để biết thêm.
Bạn không nên dựa vào [NSDate date]
mục đích thời gian vì nó có thể báo cáo quá mức hoặc quá thời gian đã trôi qua. Thậm chí có những trường hợp máy tính của bạn dường như du hành thời gian vì thời gian trôi qua sẽ âm tính! (Ví dụ: nếu đồng hồ di chuyển ngược trong thời gian.)
Theo Aria Haghighi trong bài giảng "Nhận dạng cử chỉ iOS nâng cao" của khóa học Stanford mùa đông 2013 Stanford (34:00), bạn nên sử dụng CACurrentMediaTime()
nếu bạn cần một khoảng thời gian chính xác.
Mục tiêu-C:
#import <QuartzCore/QuartzCore.h>
CFTimeInterval startTime = CACurrentMediaTime();
// perform some action
CFTimeInterval elapsedTime = CACurrentMediaTime() - startTime;
Nhanh:
let startTime = CACurrentMediaTime()
// perform some action
let elapsedTime = CACurrentMediaTime() - startTime
Lý do là [NSDate date]
đồng bộ hóa trên máy chủ, do đó, nó có thể dẫn đến "trục trặc đồng bộ hóa thời gian" có thể dẫn đến các lỗi rất khó theo dõi. CACurrentMediaTime()
mặt khác, là thời gian thiết bị không thay đổi với các đồng bộ mạng này.
Bạn sẽ cần phải thêm các khuôn khổ QuartzCore tới cài đặt của mục tiêu của bạn.
[NSDate date]
trong một khối hoàn thành trong một khối công văn, tôi đã nhận được cùng thời gian "hiện tại" đã được báo cáo [NSDate date]
ngay lập tức trước khi thực hiện đạt đến điểm mà các khối của tôi được tạo. CACurrentMediaTime()
đã giải quyết vấn đề này
CACurrentMediaTime()
dừng đánh dấu khi thiết bị đi vào giấc ngủ. Nếu bạn kiểm tra thiết bị bị ngắt kết nối với máy tính, hãy khóa thiết bị, sau đó đợi ~ 10 phút bạn sẽ thấy rằng CACurrentMediaTime()
không theo kịp thời gian của đồng hồ treo tường.
Sử dụng timeIntervalSinceDate
phương pháp
NSTimeInterval secondsElapsed = [secondDate timeIntervalSinceDate:firstDate];
NSTimeInterval
chỉ là một double
, định nghĩa NSDate
như thế này:
typedef double NSTimeInterval;
Đối với bất kỳ ai đến đây đang tìm kiếm một triển khai getTickCount () cho iOS, đây là của tôi sau khi kết hợp nhiều nguồn khác nhau.
Trước đây tôi có một lỗi trong mã này (tôi chia cho 1000000 trước), điều này gây ra một số lượng hóa đầu ra trên iPhone 6 của tôi (có lẽ đây không phải là vấn đề trên iPhone 4 / etc hoặc tôi chỉ không bao giờ nhận thấy nó). Lưu ý rằng bằng cách không thực hiện phép chia đó trước, sẽ có một số rủi ro tràn nếu tử số của cơ sở thời gian là khá lớn. Nếu có ai tò mò, có một liên kết với nhiều thông tin hơn ở đây: https://stackoverflow.com/a/23378064/588476
Trước thông tin đó, có thể an toàn hơn khi sử dụng chức năng của Apple CACurrentMediaTime
!
Tôi cũng đã điểm chuẩn mach_timebase_info
cuộc gọi và mất khoảng 19ns trên iPhone 6 của mình, vì vậy tôi đã xóa mã (không phải luồng an toàn) đang lưu trữ đầu ra của cuộc gọi đó.
#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;
}
Hãy lưu ý về nguy cơ tràn tràn tùy thuộc vào đầu ra của lệnh gọi cơ sở thời gian. Tôi nghi ngờ (nhưng không biết) rằng nó có thể là một hằng số cho mỗi mẫu iPhone. trên iPhone 6 của tôi 125/3
.
Giải pháp sử dụng CACurrentMediaTime()
khá tầm thường:
uint64_t getTickCount(void)
{
double ret = CACurrentMediaTime();
return ret * 1000;
}
mach_timebase_info()
sẽ thiết lập lại thông qua trong mach_timebase_info_data_t
để {0,0}
trước khi đặt nó vào giá trị thực tế, có thể gây ra phép chia cho không nếu mã được gọi là từ nhiều chủ đề. Sử dụng dispatch_once()
thay thế (hoặc CACurrentMediaTime
chỉ là thời gian mach được chuyển đổi thành giây).
Đối với các phép đo thời gian percise (như GetTickCount), hãy xem mach_absolute_time và Hỏi & Đáp này của Apple: http://developer.apple.com/qa/qa2004/qa1398.html .
sử dụng hàm timeIntervalSince1970 của lớp NSDate như dưới đây:
double start = [startDate timeIntervalSince1970];
double end = [endDate timeIntervalSince1970];
double difference = end - start;
về cơ bản, đây là những gì tôi sử dụng để so sánh sự khác biệt tính bằng giây giữa 2 ngày khác nhau. cũng kiểm tra liên kết này ở đây
Các câu trả lời khác là chính xác (với một cảnh báo *). Tôi thêm câu trả lời này chỉ đơn giản để hiển thị một ví dụ sử dụng:
- (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.
}
Trên bảng điều khiển trình gỡ lỗi, bạn thấy một cái gì đó như thế này:
DEBUG Method '-[XMAppDelegate getYourAffairsInOrder]' ran. Elapsed: 0.033827 seconds.
* Hãy cẩn thận: Như những người khác đã đề cập, chỉ sử dụng NSDate
để tính thời gian trôi qua cho các mục đích thông thường. Một mục đích như vậy có thể là thử nghiệm phổ biến, hồ sơ thô, trong đó bạn chỉ muốn một ý tưởng sơ bộ về thời gian thực hiện một phương pháp.
Rủi ro là cài đặt thời gian hiện tại của đồng hồ có thể thay đổi bất cứ lúc nào do đồng bộ hóa đồng hồ mạng. Vì vậy, NSDate
thời gian có thể nhảy về phía trước hoặc lùi lại bất cứ lúc nào.
fabs(...)
để có được giá trị tuyệt đối của một số float. Ví dụ.NSTimeInterval timeInterval = fabs([start timeIntervalSinceNow]);