dispatchqueue - grand central dispatch swift
¿Cómo despacho_sync, dispatch_async, dispatch_after, etc. en Swift 3, Swift 4 y más allá? (6)
Swift 4
Colas principal y de fondo
let main = DispatchQueue.main
let background = DispatchQueue.global()
let helper = DispatchQueue(label: "another_thread")
Trabajando con hilos asíncronos y sincronizados !
background.async { //async tasks here }
background.sync { //sync tasks here }
Los hilos asíncronos funcionarán junto con el hilo principal.
Los hilos de sincronización bloquearán el hilo principal mientras se ejecutan.
Tengo un montón de código en proyectos Swift 2.x (o incluso 1.x) que se ve así:
// Move to a background thread to do some long running work
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
let image = self.loadOrGenerateAnImage()
// Bounce back to the main thread to update the UI
dispatch_async(dispatch_get_main_queue()) {
self.imageView.image = image
}
}
O cosas como esta para retrasar la ejecución:
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, Int64(0.5 * Double(NSEC_PER_SEC))), dispatch_get_main_queue()) {
print("test")
}
O cualquiera de todo tipo de otros usos de Grand Central Dispatch API ...
Ahora que abrí mi proyecto en Xcode 8 (beta) para Swift 3, recibo todo tipo de errores. Algunos de ellos ofrecen arreglar mi código, pero no todas las correcciones producen código de trabajo. ¿Qué hago al respecto?
Desde el principio, Swift ha proporcionado algunas facilidades para hacer que ObjC y C sean más Swifty, agregando más con cada versión. Ahora, en Swift 3, la nueva característica "importar como miembro" permite marcos con ciertos estilos de API C, donde tiene un tipo de datos que funciona como una clase, y un montón de funciones globales para trabajar con él. actuar más como API nativas de Swift. Los tipos de datos se importan como clases Swift, sus funciones globales relacionadas se importan como métodos y propiedades en esas clases, y algunas cosas relacionadas, como conjuntos de constantes, pueden convertirse en subtipos cuando corresponda.
En Xcode 8 / Swift 3 beta, Apple ha aplicado esta función (junto con algunas otras) para hacer que el marco de Dispatch sea mucho más rápido. (Y Core Graphics , también.) Si ha estado siguiendo los esfuerzos de código abierto de Swift, esto no es una novedad , pero ahora es la primera vez que forma parte de Xcode.
El primer paso para mover cualquier proyecto a Swift 3 debe ser abrirlo en Xcode 8 y elegir Edición> Convertir> A sintaxis actual de Swift ... en el menú. Esto aplicará (con su revisión y aprobación) todos los cambios a la vez necesarios para todas las API renombradas y otros cambios. (A menudo, una línea de código se ve afectada por más de uno de estos cambios a la vez, por lo que responder a errores corregidos, es posible que no pueda manejar todo correctamente)
El resultado es que el patrón común para rebotar el trabajo en segundo plano y viceversa ahora se ve así:
// Move to a background thread to do some long running work
DispatchQueue.global(qos: .userInitiated).async {
let image = self.loadOrGenerateAnImage()
// Bounce back to the main thread to update the UI
DispatchQueue.main.async {
self.imageView.image = image
}
}
Tenga en cuenta que estamos usando
.userInitiated
lugar de una de las antiguas constantes
DISPATCH_QUEUE_PRIORITY
.
Los especificadores de calidad de servicio (QoS) se introdujeron en OS X 10.10 / iOS 8.0, proporcionando una forma más clara para que el sistema priorice el trabajo y desaproveche los antiguos especificadores de prioridad.
Consulte los
documentos
de Apple
sobre trabajo en segundo plano y eficiencia energética
para más detalles.
Por cierto, si mantiene sus propias colas para organizar el trabajo, la forma de obtener uno ahora se ve así (tenga en cuenta que
DispatchQueueAttributes
es un
OptionSet
, por lo que usa literales de estilo de colección para combinar opciones):
class Foo {
let queue = DispatchQueue(label: "com.example.my-serial-queue",
attributes: [.serial, .qosUtility])
func doStuff() {
queue.async {
print("Hello World")
}
}
}
¿Usando
dispatch_after
para hacer el trabajo más tarde?
Ese también es un método en colas, y se necesita un
DispatchTime
, que tiene operadores para varios tipos numéricos para que pueda agregar segundos enteros o fraccionarios:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) { // in half a second...
print("Are we there yet?")
}
Puede orientarse en la nueva API Dispatch abriendo su interfaz en Xcode 8: use Abrir rápidamente para buscar el módulo Dispatch, o coloque un símbolo (como
DispatchQueue
) en su proyecto / área de juegos Swift y haga clic en el comando, luego pase alrededor del módulo desde allí.
(Puede encontrar la API Swift
Dispatch
en el nuevo y sofisticado sitio web de referencia de API de Apple y en el visor de documentos en Xcode, pero parece que el contenido de documentos de la versión C aún no se ha movido).
Consulte la Guía de migración para obtener más consejos.
En Xcode 8 beta 4 no funciona ...
Utilizar:
DispatchQueue.main.asyncAfter(deadline: .now() + 0.5) {
print("Are we there yet?")
}
para asíncrono de dos maneras:
DispatchQueue.main.async {
print("Async1")
}
DispatchQueue.main.async( execute: {
print("Async2")
})
Este es un buen ejemplo para
Swift 4
sobre
async
:
DispatchQueue.global(qos: .background).async {
// Background Thread
DispatchQueue.main.async {
// Run UI Updates or call completion block
}
}
en Xcode 8 use:
DispatchQueue.global(qos: .userInitiated).async { }
Swift 4.1 y 5. Utilizamos colas en muchos lugares de nuestro código. Entonces, creé la clase Threads con todas las colas. Si no desea utilizar la clase Threads, puede copiar el código de cola deseado de los métodos de clase.
class Threads {
static let concurrentQueue = DispatchQueue(label: "AppNameConcurrentQueue", attributes: .concurrent)
static let serialQueue = DispatchQueue(label: "AppNameSerialQueue")
// Main Queue
class func performTaskInMainQueue(task: @escaping ()->()) {
DispatchQueue.main.async {
task()
}
}
// Background Queue
class func performTaskInBackground(task:@escaping () throws -> ()) {
DispatchQueue.global(qos: .background).async {
do {
try task()
} catch let error as NSError {
print("error in background thread:/(error.localizedDescription)")
}
}
}
// Concurrent Queue
class func perfromTaskInConcurrentQueue(task:@escaping () throws -> ()) {
concurrentQueue.async {
do {
try task()
} catch let error as NSError {
print("error in Concurrent Queue:/(error.localizedDescription)")
}
}
}
// Serial Queue
class func perfromTaskInSerialQueue(task:@escaping () throws -> ()) {
serialQueue.async {
do {
try task()
} catch let error as NSError {
print("error in Serial Queue:/(error.localizedDescription)")
}
}
}
// Perform task afterDelay
class func performTaskAfterDealy(_ timeInteval: TimeInterval, _ task:@escaping () -> ()) {
DispatchQueue.main.asyncAfter(deadline: (.now() + timeInteval)) {
task()
}
}
}
Ejemplo que muestra el uso de la cola principal.
override func viewDidLoad() {
super.viewDidLoad()
Threads.performTaskInMainQueue {
//Update UI
}
}