Как приостановить рабочий элемент в главной очереди - PullRequest
0 голосов
/ 02 декабря 2018

Я хочу знать, возможно ли приостановить, а затем возобновить рабочий элемент в главной очереди, сохраняя при этом время «.asyncAfter».Если нет, есть ли обходной путь для достижения этой цели?

В определенный момент я ставлю в очередь следующий DispatchWorkItem:

dispatchWorkItem = DispatchWorkItem(qos: .userInteractive, block: {
            self.view.backgroundColor = UIColor.workoutBackgroundColor
            self.runTimer()
            self.timerButton.animateableTrackLayer.removeAnimation(forKey: "strokeEndAnimation")
            self.isRestState = false
        })

Я ставлю это в очередь, используя:

    DispatchQueue.main.asyncAfter(deadline: delayTime, execute: self.dispatchWorkItem))

(delayTime является параметром для функции)

Теперь проблема, с которой я сталкиваюсь, заключается в том, как я могу приостановить этот рабочий элемент, если пользователь выполняет действие «пауза» в моем приложении.

Я пытался использовать метод DispatchQueue.main.suspend(), но рабочий элемент продолжает выполняться после указанного времени задержки.Из того, что я прочитал, этот метод должен приостановить очередь и этот рабочий элемент из очереди, поскольку он не выполняется.(Пожалуйста, исправьте меня, если я ошибаюсь!)

Мне нужно добиться, чтобы рабочий элемент был «приостановлен», пока пользователь не выполнит действие «возобновить» в приложении, которое возобновит рабочий элемент, откудавремя задержки остановилось.

Это работает с фоновыми очередями, которые я создал, когда мне не нужно обновлять пользовательский интерфейс;тем не менее, в основной очереди, кажется, происходит сбой.

Один из обходных путей, который я рассмотрел, - это когда пользователь выполняет действие паузы, сохраняя время, оставшееся до выполнения рабочего элемента, и повторно добавляя работу.элемент в очередь с указанным временем действия возобновления.Это выглядит как некачественный подход, и я чувствую, что для этого есть более подходящий метод.

На этом, возможно ли создать фоновую очередь, которая при выполнении выполняет рабочий элемент в главной очереди?

Заранее спасибо!

1 Ответ

0 голосов
/ 03 декабря 2018

Можно ли создать фоновую очередь, которая при выполнении выполняет рабочий элемент в главной очереди?

Вы предлагаете что-то вроде этого:

var q = DispatchQueue(label: "myqueue")
func configAndStart(seconds:TimeInterval, handler:@escaping ()->Void) {
    self.q.asyncAfter(deadline: .now() + seconds, execute: {
        DispatchQueue.main.async(execute: handler())
    })
}
func pause() {
    self.q.suspend()
}
func resume() {
    self.q.resume()
}

Но мои настоящие тесты, похоже, показывают, что это не сработает, как вы хотите;обратный отсчет не возобновляется с того места, где он был приостановлен.

Один из обходных путей, который я рассмотрел, - это когда пользователь выполняет действие паузы, сохраняя время, оставшееся до выполнения рабочего элемента, и повторно добавляя рабочий элемент в очередь с этим временем.возобновить действие.Это похоже на некачественный подход, и я считаю, что для этого есть более подходящий метод.

Это не плохое качество.Не существует встроенного механизма для приостановки обратного отсчета таймера диспетчеризации или для анализа таймера, поэтому, если вы хотите сделать все это в главной очереди, ваш единственный выход - это то, что вы сказали: поддерживать свой собственный таймер и необходимое состояниепеременные.Вот довольно глупый макет, который я собрал вместе:

class PausableTimer {
    var t : DispatchSourceTimer!
    var d : Date!
    var orig : TimeInterval = 0
    var diff : TimeInterval = 0
    var f : (()->Void)!
    func configAndStart(seconds:TimeInterval, handler:@escaping ()->Void) {
        orig = seconds
        f = handler
        t = DispatchSource.makeTimerSource()
        t.schedule(deadline: DispatchTime.now()+orig, repeating: .never)
        t.setEventHandler(handler: f)
        d = Date()
        t.resume()
    }
    func pause() {
        t.cancel()
        diff = Date().timeIntervalSince(d)
    }
    func resume() {
        orig = orig-diff
        t = DispatchSource.makeTimerSource()
        t.schedule(deadline: DispatchTime.now()+orig, repeating: .never)
        t.setEventHandler(handler: f)
        t.resume()
    }
}

Это сработало в моем грубом тестировании и, кажется, прерывается (пауза), как хотелось бы, но не цитируйте меня;Я не тратил много времени на это.Подробности оставлены в качестве упражнения для читателя!

...