ios - dispatchqueue - nsoperationqueue swift 3 example
¿Cómo escribo dispatch_after GCD en Swift 3, 4 y 5? (13)
En Swift 2, pude usar
dispatch_after
para retrasar una acción usando grand central dispatch:
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
})
Pero esto ya no parece compilarse desde Swift 3. ¿Cuál es la forma preferida de escribir esto en Swift moderno?
En Swift 4.1 y Xcode 9.4.1
La respuesta simple es ...
//To call function after 5 seconds time
DispatchQueue.main.asyncAfter(deadline: .now() + 5.0) {
//Here call your function
}
Esto funcionó para mí en Swift 3
let time1 = 8.23
let time2 = 3.42
// Delay 2 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 2.0) {
print("Sum of times: /(time1 + time2)")
}
La sintaxis es simplemente:
// to run something in 0.1 seconds
DispatchQueue.main.asyncAfter(deadline: .now() + 0.1) {
// your code here
}
Tenga en cuenta que la sintaxis anterior de agregar
seconds
como
Double
parece ser una fuente de confusión (especialmente porque estábamos acostumbrados a agregar nsec).
Esa sintaxis de "agregar segundos como
Double
" funciona porque la
deadline
es un tiempo de
DispatchTime
y, detrás de escena, hay un operador
+
que tomará un
Double
y agregará tantos segundos al tiempo de
DispatchTime
:
public func +(time: DispatchTime, seconds: Double) -> DispatchTime
Pero, si realmente desea agregar un número entero de mseg, μs o nsec al
DispatchTime
, también puede agregar un
DispatchTimeInterval
a un
DispatchTime
.
Eso significa que puedes hacer:
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")
}
Todo esto funciona a la perfección debido a este método de sobrecarga separado para el operador
+
en la clase
DispatchTime
.
public func +(time: DispatchTime, interval: DispatchTimeInterval) -> DispatchTime
Se le preguntó cómo se cancela una tarea despachada.
Para hacer esto, use
DispatchWorkItem
.
Por ejemplo, esto inicia una tarea que se activará en cinco segundos, o si el controlador de vista se descarta y se desasigna, su
deinit
cancelará la tarea:
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() { ... }
}
Tenga en cuenta el uso de la lista de captura
[weak self]
en
DispatchWorkItem
.
Esto es esencial para evitar un ciclo de referencia fuerte.
También tenga en cuenta que esto no hace una cancelación preventiva, sino que simplemente detiene la tarea de comenzar si aún no lo ha hecho.
Pero si ya ha comenzado cuando se encuentra con la llamada
cancel()
, el bloque finalizará su ejecución (a menos que esté verificando manualmente
isCancelled
dentro del bloque).
Ninguna de las respuestas mencionó ejecutarse en un hilo no principal, por lo que agregué mis 2 centavos.
En la cola principal (hilo principal)
let mainQueue = DispatchQueue.main
let deadline = DispatchTime.now() + .seconds(10)
mainQueue.asyncAfter(deadline: deadline) {
// ...
}
O
DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + .seconds(10)) {
// ...
}
En cola global (subproceso no principal, basado en QOS especificado).
let backgroundQueue = DispatchQueue.global()
let deadline = DispatchTime.now() + .milliseconds(100)
backgroundQueue.asyncAfter(deadline: deadline, qos: .background) {
// ...
}
O
DispatchQueue.global().asyncAfter(deadline: DispatchTime.now() + .milliseconds(100), qos: .background) {
// ...
}
Puedes usar
DispatchQueue.main.asyncAfter(deadline: .now() + .microseconds(100)) {
// Code
}
Si solo quieres la función de retraso en
Swift 4 y 5
func delay(interval: TimeInterval, closure: @escaping () -> Void) {
DispatchQueue.main.asyncAfter(deadline: .now() + interval) {
closure()
}
}
Puedes usarlo como:
delay(interval: 1) {
print("Hi!")
}
Un sabor algo diferente de la respuesta aceptada.
Swift 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)")
}
después del lanzamiento de Swift 3, también se debe agregar @escaping
func delay(_ delay: Double, closure: @escaping () -> ()) {
DispatchQueue.main.asyncAfter(deadline: .now() + delay) {
closure()
}
}
llame a
DispatchQueue.main.after(when: DispatchTime, execute: () -> Void)
Recomiendo encarecidamente utilizar las herramientas de Xcode para convertir a Swift 3 (Edición> Convertir> A sintaxis Swift actual). Esto me atrapó
prueba esto
let when = DispatchTime.now() + 1.5
DispatchQueue.main.asyncAfter(deadline: when) {
//some code
}
Swift 4
Puede crear una extensión en DispatchQueue y agregar un retraso de función que use la función
DispatchQueue
asyncAfter internamente
extension DispatchQueue {
static func delay(_ delay: DispatchTimeInterval, closure: @escaping () -> ()) {
DispatchQueue.main.asyncAfter(deadline: .now() + delay, execute: closure)
}
}
y use
DispatchQueue.delay(.milliseconds(10)) {
print("task to be done")
}
Swift 4:
DispatchQueue.main.asyncAfter(deadline: .now() + .milliseconds(100)) {
// Code
}
Por el momento, se pueden
.seconds(Int)
,
.microseconds(Int)
y
.nanoseconds(Int)
.
Swift 5 y superior
DispatchQueue.main.asyncAfter(deadline: .now() + 2, execute: {
// code to execute
})