如何在主队列上挂起工作项

时间:2018-12-02 20:55:59

标签: swift grand-central-dispatch

我想知道是否有可能在保持“ .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()方法,但是工作项在指定的延迟时间后继续执行。据我所读,此方法应该暂停队列和此排队的工作项,因为它没有被执行。 (如果我错了,请纠正我!)

我需要实现的是工作项目被“暂停”,直到用户在应用程序中执行“恢复”操作为止,该操作将从延迟时间停止的地方恢复工作项目。

这适用于不需要进行UI更新时创建的后台队列。但是,在主队列上似乎步履蹒跚。

我考虑过的一种解决方法是,用户执行暂停动作时,存储直到将要执行工作项为止的剩余时间,然后在恢复动作中将该时间重新添加到队列中。这似乎是质量很差的方法,我觉得有一种更合适的方法。

是否可以创建一个在执行时在主队列上执行工作项目的后台队列?

谢谢!

1 个答案:

答案 0 :(得分:3)

  

是否可以创建一个在执行时在主队列上执行工作项目的后台队列?

您建议的是这样的

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()
    }
}

这在我的粗略测试中有效,并且似乎可以根据需要中断(可暂停),但是请不要引用我;我没有花很多时间。这些细节留给读者练习!