ChatGPT解决这个技术问题 Extra ChatGPT

如何在 Swift 3、4 和 5 中编写 dispatch_after GCD?

在 Swift 2 中,我可以使用 dispatch_after 来延迟使用大型中央调度的操作:

var dispatchTime: dispatch_time_t = dispatch_time(DISPATCH_TIME_NOW, Int64(0.1 * Double(NSEC_PER_SEC))) 
dispatch_after(dispatchTime, dispatch_get_main_queue(), { 
    // your function here 
})

但这似乎从 Swift 3 开始不再编译。在现代 Swift 中编写它的首选方法是什么?

可以在此处找到有关迁移过程的更多信息:https://swift.org/migration-guide/“调度”部分与此问题相关
你的问题应该是UInt64吗?

R
Rob

语法很简单:

// to run something in 0.1 seconds

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
    // your code here
}

请注意,将 seconds 添加为 Double 的上述语法似乎是混淆的来源(尤其是因为我们习惯于添加 nsec)。 “将秒数添加为 Double”语法有效,因为 deadlineDispatchTime,并且在幕后,有一个 + 运算符将采用 Double 并将那么多秒数添加到 DispatchTime

public func +(time: DispatchTime, seconds: Double) -> DispatchTime

但是,如果您确实想将整数 msec、μs 或 nsec 添加到 DispatchTime,您也可以将 DispatchTimeInterval 添加到 DispatchTime。这意味着你可以这样做:

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(500)) {
    os_log("500 msec seconds later")
}

DispatchQueue.main.asyncAfter(deadline: .now() + .microseconds(1_000_000)) {
    os_log("1m μs seconds later")
}

DispatchQueue.main.asyncAfter(deadline: .now() + .nanoseconds(1_500_000_000)) {
    os_log("1.5b nsec seconds later")
}

由于 DispatchTime 类中 + 运算符的这种单独的重载方法,这些都可以无缝地工作。

public func +(time: DispatchTime, interval: DispatchTimeInterval) -> DispatchTime

有人询问如何取消已分派的任务。为此,请使用 DispatchWorkItem。例如,这将启动一个将在 5 秒内触发的任务,或者如果视图控制器被解除并释放,它的 deinit 将取消该任务:

class ViewController: UIViewController {

    private var item: DispatchWorkItem?

    override func viewDidLoad() {
        super.viewDidLoad()

        item = DispatchWorkItem { [weak self] in
            self?.doSomething()
            self?.item = nil
        }

        DispatchQueue.main.asyncAfter(deadline: .now() + 5, execute: item!)
    }

    deinit {
        item?.cancel()
    }

    func doSomething() { ... }

}

请注意 DispatchWorkItem[weak self] 捕获列表的使用。这对于避免强参考循环至关重要。另请注意,这不会进行抢先取消,而只是阻止任务启动(如果尚未启动)。但是,如果它在遇到 cancel() 调用时已经启动,则该块将完成其执行(除非您在块内手动检查 isCancelled)。


感谢您指出这一点,事实上 swift.org/migration-guide 提到需要手动进行更改。
哦对不起。这里太晚了:)。以为所有的烂摊子都应该去,但没有迈出这一步。 IMO“简单”的解决方案是唯一的解决方案。
@Rob我将如何取消它?谢谢。
好的,那么如何添加动态等待?例如,我有一个让数:Float = 1.0。并且 .now() + .milliseconds(number) 不起作用。 Double(number) 也没有。我想不通。
DispatchTimeInterval 演绎版(如 .milliseconds)需要 Int。但如果只是增加秒数,我会使用 Double,例如 let n: Double = 1.0; queue.asyncAfter(deadline: .now() + n) { ... }
S
Sverrisson

斯威夫特 4:

DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {
   // Code
}

对于时间 .seconds(Int),也可以使用 .microseconds(Int).nanoseconds(Int)


.milliseconds 优于 Double。
非常好。给其他人的注意事项:您也可以使用任何其他 DispatchTimeInterval 枚举值。 case seconds(Int) case milliseconds(Int) case microseconds(Int) case nanoseconds(Int)
@RobMacEachern,谢谢这是一个很好的建议,我将其添加到答案中。
.milliseconds is better than Double. ——我想把它印在 T 恤上;)。
r
rockdaswift

如果你只想要延迟功能

斯威夫特 4 & 5

func delay(interval: TimeInterval, closure: @escaping () -> Void) {
     DispatchQueue.main.asyncAfter(deadline: .now() + interval) {
          closure()
     }
}

你可以像这样使用它:

delay(interval: 1) { 
    print("Hi!")
}

DispatchQueue.main.asyncAfter(deadline: ) 不起作用。它说它不会重载其超类中的任何方法。
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1, execute: closure) 更简单。
M
Marco Pappalardo

在 Swift 3 发布之后,还必须添加 @escaping

func delay(_ delay: Double, closure: @escaping () -> ()) {
  DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
    closure()
  }
}

M
Md. Ibrahim Hassan

接受的答案有点不同的味道。

斯威夫特 4

DispatchQueue.main.asyncAfter(deadline: .now() + 0.1 + .milliseconds(500) + 
.microseconds(500) + .nanoseconds(1000)) {
                print("Delayed by 0.1 second + 500 milliseconds + 500 microseconds + 
                      1000 nanoseconds)")
 }

S
Suhit Patil

斯威夫特 4

您可以在 DispatchQueue 上创建扩展并添加在内部使用 DispatchQueue asyncAfter 函数的函数延迟

extension DispatchQueue {
   static func delay(_ delay: DispatchTimeInterval, closure: @escaping () -> ()) {
      DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: closure)
   }
}

并使用

DispatchQueue.delay(.milliseconds(10)) {
   print("task to be done")
}

这与@rockdaswift 的回答有何不同?
正如我所提到的,它将 asyncAfter 包装在 performAfter 函数中,该函数将延迟作为参数,并且使用 performAfter(delay: 2) { } 可以更容易地调用
闭包参数默认是非转义的,@escaping 表示闭包参数可以转义。在闭包中添加了@转义参数以保存潜在的崩溃。
j
jjatie

呼叫 DispatchQueue.main.after(when: DispatchTime, execute: () -> Void)

我强烈建议使用 Xcode 工具转换为 Swift 3(编辑 > 转换 > 到当前的 Swift 语法)。它为我捕捉到了这个


m
midhun p

斯威夫特 5 及以上

DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
   // code to execute                 
})

M
MANN

没有提到在非主线程上运行的答案,所以加上我的 2 美分。

在主队列(主线程)

let mainQueue = DispatchQueue.main
let deadline = DispatchTime.now() + .seconds(10)
mainQueue.asyncAfter(deadline: deadline) {
    // ...
}

或者

DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(10)) { 
    // ...
}

在全局队列上(非主线程,基于指定的 QOS)。

let backgroundQueue = DispatchQueue.global()
let deadline = DispatchTime.now() + .milliseconds(100)
backgroundQueue.asyncAfter(deadline: deadline, qos: .background) { 
    // ...
}

或者

DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + .milliseconds(100), qos: .background) {
    // ...
}