Về cơ bản, bạn không có bảo đảm nào với NSTimer
hoặc dispatch_after
; họ lên lịch mã để kích hoạt trên luồng chính, nhưng nếu cái gì khác mất một thời gian dài để thực thi và chặn luồng chính, bộ hẹn giờ của bạn sẽ không kích hoạt.
Điều đó nói rằng, bạn có thể dễ dàng tránh việc chặn luồng chính (chỉ sử dụng I/O không đồng bộ) và mọi thứ sẽ khá tốt.
Bạn không nói chính xác những gì bạn cần làm trong mã bộ hẹn giờ, nhưng nếu tất cả những gì bạn cần làm là hiển thị đếm ngược, bạn sẽ ổn khi bạn tính thời gian SMPTE dựa trên thời gian hệ thống, và không phải số giây bạn cho là đã trôi qua dựa trên khoảng thời gian của bạn. Nếu bạn làm điều đó, bạn gần như chắc chắn sẽ trôi dạt và không đồng bộ với thời gian thực tế. Thay vào đó, hãy lưu ý thời gian bắt đầu của bạn và sau đó thực hiện tất cả toán học dựa trên điều đó:
// Setup
timerStartDate = [[NSDate alloc] init];
[NSTimer scheduledTimer...
- (void)timerDidFire:(NSTimer *)timer
{
NSTImeInterval elapsed = [timerStartDate timeIntervalSinceNow];
NSString *smtpeCode = [self formatSMTPEFromMilliseconds:elapsed];
self.label.text = smtpeCode;
}
Bây giờ bạn sẽ hiển thị mã thời gian chính xác bất kể tần suất được kích hoạt. (Nếu bộ hẹn giờ không kích hoạt thường xuyên, bộ hẹn giờ sẽ không cập nhật, nhưng khi nó cập nhật nó sẽ chính xác. Nó sẽ không bao giờ bị đồng bộ.)
Nếu bạn sử dụng CADisplayLink, phương pháp của bạn sẽ được gọi nhanh như cập nhật hiển thị. Nói cách khác, nhanh như nó sẽ hữu ích, nhưng không nhanh hơn. Nếu bạn đang hiển thị thời gian, đó có thể là cách để đi.
Lưu ý rằng _frameInterval_ không được chấp nhận trong iOS 10.0, sử dụng _preferredFramesPerSecond_, như sau: 'displayLink.preferredFramesPerSecond = 30.0;' cho 30fps – WongWray