2016-12-06 4 views
6

Я пытаюсь вызвать функцию после задержки. На iOS10 я могу использовать Timer.scheduledTimer, который действительно вызывает мое закрытие после данной задержки. Однако на iOS9 я использую DispatchQueue.main.asyncAfter, и он вызывает мое закрытие с задержкой в ​​шесть секунд.DispatchQueue.main.asyncAfter неточно

Задержка, которую я тестирую, составляет 60 секунд. Timer.scheduledTimer вызывает закрытие через 60 секунд, DispatchQueue.main.async Через 66 секунд. Задержка в шесть секунд является следствием, если я планирую два задержек на 60 секунд, вторая задержка вызывается через 132 секунды, используя 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() 
     } 
    } 
} 

Код, который вызывает функцию задержки:

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.") 
} 

уведомления и методы планирования вызовов с использованием 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. 

Пауза называется:

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 

Запланированные в 13:34 : 06, названный в 13:35:06

уведомлений и методов планирования вызовов с использованием 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. 

Пауза называется:

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 

Планируемое в в 13:36: 48, позвонил по телефону 13:37:54

ответ

9

asyncAfter гарантированно будет ждать не меньше указанного срока.

Возможно, вам все равно нужно использовать таймер, если вы хотите, чтобы на iOS9 были установлены точные временные интервалы.

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

С исполнением является функция, выполняющая последнее сохраненное закрытие.

+0

Спасибо, это имеет смысл. Я думаю, что происходит, что выполнение кода задерживает основной поток в течение шести секунд. Между каждым сеансом исследования и паузы я подключаюсь к VPN. Первоначально я использовал Timer для iOS9, но параметр селектора вызвал некоторые проблемы, потому что функция принимает один параметр. XCode хотел, чтобы я добавил @objc к моему методу. Я посмотрю, как разрешить это и придерживаться Timer для обеих версий iOS. –

+3

У меня также возникла эта проблема ('asyncAfter' не точный). В моем случае было всегда поздно около 10%, чем ожидалось. Я был удивлен, что это единственное обсуждение, которое я нашел на эту тему, поэтому я просто подумал, откуда вы знаете, что «asyncAfter» гарантированно будет ждать хотя бы столько, сколько указано «@ tristan-burnside»? :) Я не мог найти официальных документов по этому вопросу. – tadija

+0

Я тоже был в этой проблеме, пытаясь обобщить некоторые функции отсрочки события и хотел, чтобы это было сделано с помощью gcd, но в конечном итоге я использовал таймер, поскольку это имеет смысл. Надеюсь, никто не будет тратить время (~ 5 часов), как я. Спасибо, Тристан –

Смежные вопросы