В последнее время я использую dispatch_after вместо executeSelector: withObject: afterDelay, когда я хочу запускать некоторый код после задержки. Код чище, он имеет доступ к охватывающей области, я могу поместить код в строку вместо написания метода выброса и т.д. И т.д.
Мой код может выглядеть так:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
delay * NSEC_PER_SEC),
dispatch_get_main_queue(),
^{
//Delayed-execution code goes here.
}
);
Однако недавно я обнаружил, что время от времени из этого кода работает довольно последовательно примерно на 10% медленнее, чем требуется. Если я попрошу задержку в 10 секунд, мой блок будет выполнен примерно через 11 секунд. Это на устройстве iOS. Время, похоже, довольно близко соответствует симулятору.
Код, который я использую для тестирования, довольно прост:
NSTimeInterval startTime = [NSDate timeIntervalSinceReferenceDate];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
delay * NSEC_PER_SEC),
dispatch_get_main_queue(),
^{
NSTimeInterval actualDelay = [NSDate timeIntervalSinceReferenceDate] - startTime;
NSLog(@"Requested delay = %.3f. Atual delay = %.3f", delay, actualDelay);
//Delayed-execution code goes here.
}
);
Я тестировал устройства с iOS 4S на iPad Air, и дополнительная задержка довольно последовательна. Я еще не тестировал более старое устройство, такое как iPhone 4 или iPad 2, хотя я скоро это сделаю.
Я мог бы ожидать 20-50 мс "отскока" в задержке, но непротиворечивость 10% - 11% нечетна.
Я добавил в код код "fudge factor", который настраивается для дополнительной задержки, но я нахожу это удивительным:
#define delay_fudge 0.912557 //Value calculated based on averages from testing.
NSTimeInterval startTime = [NSDate timeIntervalSinceReferenceDate];
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
delay * delay_fudge * NSEC_PER_SEC),
dispatch_get_main_queue(),
^{
NSTimeInterval actualDelay = [NSDate timeIntervalSinceReferenceDate] - startTime;
NSLog(@"Requested delay = %.3f. Actual delay = %.3f", delay, actualDelay);
//Delayed-execution code goes here.
}
);
Я должен, вероятно, сделать больше анализа и посмотреть, есть ли фиксированное увеличение задержки плюс коэффициент задержки или прямая процентная задержка или, возможно, некоторый нелинейный масштаб ошибки, но на данный момент простой множитель, кажется, делает довольно хорошо.