Czy zauważyłeś, że dispatch_after działa ~ 10% za wolno na urządzeniach z systemem iOS?
Ostatnio używam dispatch_after zamiast performSelector: withObject: afterDelay, kiedy chcę wyzwolić jakiś kod po pewnym czasie. Kod jest czystszy, ma dostęp do otaczającego zakresu, mogę umieścić kod w linii zamiast pisać metodę wyrzucania itp. Itd.
Mój kod może wyglądać tak:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW,
delay * NSEC_PER_SEC),
dispatch_get_main_queue(),
^{
//Delayed-execution code goes here.
}
);
Niedawno jednak odkryłem, że czas na wykrycie tego kodu wydaje się działać dość konsekwentnie około 10% wolniej niż zażądano. Jeśli poproszę o opóźnienie 10 sekund, mój blok zostanie wykonany około 11 sekund później. To jest na urządzeniu z systemem iOS. Czasy wydają się pasować dość dokładnie na symulatorze.
Kod, którego używam do testowania tego, jest całkiem prosty:
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.
}
);
Przetestowałem na urządzeniach z iOS 4S do iPada Air, a dodatkowe opóźnienie jest dość spójne. Jeszcze nie testowałem na starszym urządzeniu, takim jak iPhone 4 lub iPad 2, chociaż wkrótce to zrobię.
Mogę spodziewać się 20-50 ms „opóźnienia” w opóźnieniu, ale spójne 10% - 11% przeregulowania jest dziwne.
Dodałem „kod krówki” do mojego kodu, który dostosowuje się do dodatkowego opóźnienia, ale wydaje mi się to zaskakujące:
#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.
}
);
Prawdopodobnie powinienem zrobić więcej analiz i sprawdzić, czy istnieje stały wzrost opóźnienia plus współczynnik opóźnienia lub proste procentowe opóźnienie, a może jakaś nieliniowa skala błędu, ale na razie prosty mnożnik wydaje się całkiem dobrze.