2016-12-06 9 views
6

Próbuję wywołać funkcję po opóźnieniu. Na iOS10 mogę używać Timer.scheduledTimer, który rzeczywiście wywołuje moje zamknięcie po określonym opóźnieniu. Jednak na iOS9 używam DispatchQueue.main.asyncAfter i wywołuje on moje zamknięcie z sześciosekundowym opóźnieniem.DispatchQueue.main.asyncAfter jest niedokładna

Opóźnienie, z którym testuję, wynosi 60 sekund. Timer.scheduledTimer wywołuje zamknięcie po 60 sekundach, DispatchQueue.main.asyncAfter po 66 sekundach. Sześć sekund opóźnienia jest konsekwencją, jeśli zaplanuje dwa opóźnienia 60 sekund, drugie opóźnienie jest wywoływane po 132 sekundach przy użyciu DispatchQueue.main.asyncAfter.

func delay(delay:Double, closure:@escaping()->()) { 
    NSLog("Calling method with delay of: \(delay)") 

    if #available(iOS 10.0, *) { 
     Timer.scheduledTimer(withTimeInterval: delay, repeats: false) { (timer) in 
      closure() 
     } 
    } else { 
     // TODO: Is not accurate, delay of +- 6 seconds 
     DispatchQueue.main.asyncAfter(deadline: .now() + delay) { 
      closure() 
     } 
    } 
} 

Kod, który wywołuje funkcję Opóźnienie:

func scheduleStudy(minutes: Int, secondsFromNow: Int) { 
    // Study notification 
    if #available(iOS 10.0, *) { 
     self.addiOS10StudyNotification(minutes: minutes, secondsFromNow: secondsFromNow) 
    }else{ 
     self.addiOS9StudyNotification(minutes: minutes, secondsFromNow: secondsFromNow) 
    } 

    // Study timer 
    delay(delay: Double(secondsFromNow)) { 
     self.onStudy(minutes: minutes) 
    } 

    NSLog("Scheduled study for \(minutes) minutes in \(secondsFromNow) seconds from now.") 
} 

zawiadomienia oraz metod planowania połączeń przy użyciu Timer.scheduledTimer

2016-12-06 13:34:06.024714 Mattie[1386:360881] Calling method with delay of: 0.0 
2016-12-06 13:34:06.025072 Mattie[1386:360881] Scheduled study for 1 minutes in 0 seconds from now. 
2016-12-06 13:34:06.036953 Mattie[1386:360881] Calling method with delay of: 60.0 
2016-12-06 13:34:06.037191 Mattie[1386:360881] Scheduled pause for 1 minutes in 60 seconds from now. 
2016-12-06 13:34:06.052520 Mattie[1386:360881] Calling method with delay of: 120.0 
2016-12-06 13:34:06.053162 Mattie[1386:360881] Scheduled study for 1 minutes in 120 seconds from now. 
2016-12-06 13:34:06.066838 Mattie[1386:360881] Calling method with delay of: 180.0 
2016-12-06 13:34:06.067027 Mattie[1386:360881] Scheduled finish in 180 seconds from now. 

Pauza nazywa się:

2016-12-06 13:35:06.038307 Mattie[1386:360881] ON PAUSE 
2016-12-06 13:35:06.065389 Mattie[1386:360881] Added pause timer for 1 minutes 

Planned w 13:34 : 06, zwany w 13:35:06

powiadomień i metod planowania połączeń przy użyciu DispatchQueue.main.asyncAfter

2016-12-06 13:36:48.845838 Mattie[1390:361681] Calling method with delay of: 0.0 
2016-12-06 13:36:48.847389 Mattie[1390:361681] Scheduled study for 1 minutes in 0 seconds from now. 
2016-12-06 13:36:48.854336 Mattie[1390:361681] Calling method with delay of: 60.0 
2016-12-06 13:36:48.854543 Mattie[1390:361681] Scheduled pause for 1 minutes in 60 seconds from now. 
2016-12-06 13:36:48.861424 Mattie[1390:361681] Calling method with delay of: 120.0 
2016-12-06 13:36:48.861601 Mattie[1390:361681] Scheduled study for 1 minutes in 120 seconds from now. 
2016-12-06 13:36:48.868464 Mattie[1390:361681] Calling method with delay of: 180.0 
2016-12-06 13:36:48.868644 Mattie[1390:361681] Scheduled finish in 180 seconds from now. 

Pauza nazywa się:

2016-12-06 13:37:54.865400 Mattie[1390:361681] ON PAUSE 
2016-12-06 13:37:54.897354 Mattie[1390:361681] Added pause timer for 1 minutes 

zaplanowana na 13:36: 48, wywołany o 13:37:54

Odpowiedz

9

asyncAfter może tylko czekać co najmniej tak długo, jak określono.

Prawdopodobnie powinieneś nadal używać Timera, jeśli chcesz dokładnych interwałów czasowych w iOS9.

Timer.scheduledTimer(timeInterval: delay, 
       target: self, 
      selector: #selector(executeClosure), 
      userInfo: nil, 
       repeats: false) 

Z executeClosure będącym funkcją, która wykonuje ostatnie zapisane zamknięcie.

+0

Dzięki, to ma sens. Myślę, że dzieje się tak, że wykonanie kodu opóźnia główny wątek przez sześć sekund. Pomiędzy każdą sesją badania i przerwą łączę się z VPN. Pierwotnie użyłem także Timera dla iOS9, ale parametr selektora spowodował pewne problemy, ponieważ funkcja przyjmuje jeden parametr. XCode chciał, abym dodał @objc do mojej metody. Zobaczę, jak rozwiązać ten problem i trzymać się timera dla obu wersji systemu iOS. –

+3

Wystąpił również ten problem ("asyncAfter" nie jest dokładny). W moim przypadku było to zawsze spóźnione około 10%, niż się spodziewano. Byłem zaskoczony, że jest to jedyna dyskusja, jaką znalazłem na ten temat, więc zastanawiałem się tylko, skąd wiedziałeś, że "asyncAfter" gwarantuje tylko czekanie co najmniej tak długo jak określono '@ tristan-burnside? :) Nie mogłem znaleźć żadnych oficjalnych dokumentów na ten temat. – tadija

+0

Byłem też w tym problemie, próbując uogólnić niektóre funkcje odraczania zdarzeń i chciałbym, żeby to było zrobione z gcd, ale w końcu sam wykorzystałem timer, ponieważ ma to sens. Mam nadzieję, że nikt nie zmarnuje czasu (~ 5h) jak ja. Dzięki Tristan –

Powiązane problemy