¿Cómo puedo despacho_sync, despacho_async, despacho_after, etc. en Swift 3, Swift 4 y más allá?

Resuelto rickster asked hace 8 años • 6 respuestas

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 todos los tipos de otros usos de la API de Grand Central Dispatch...

Ahora que abrí mi proyecto en Xcode 8 (beta) para Swift 3, aparece todo tipo de errores. Algunos de ellos ofrecen arreglar mi código, pero no todas las correcciones producen un código que funcione. ¿Qué hago al respecto?

rickster avatar Jun 14 '16 07:06 rickster
Aceptado

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 tienes un tipo de datos que funciona como una clase y un montón de funciones globales para trabajar con él. actúan 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 aplicó esta característica (junto con algunas otras) para hacer que el marco de Dispatch sea mucho más Swifty. (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.

Su primer paso para mover cualquier proyecto a Swift 3 debería ser abrirlo en Xcode 8 y elegir Editar > Convertir > A la sintaxis Swift actual... en el menú. Esto aplicará (con su revisión y aprobación) todos los cambios necesarios a la vez para todas las API cuyo nombre cambió 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 la corrección de errores individualmente puede no manejar todo correctamente).

El resultado es que el patrón común para rebotar el trabajo hacia el fondo 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 .userInitiateden lugar de una de las antiguas DISPATCH_QUEUE_PRIORITYconstantes. 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 desaprobando los antiguos especificadores de prioridad. Consulte los documentos de Apple sobre trabajo en segundo plano y eficiencia energética para obtener más detalles.

Por cierto, si mantienes tus propias colas para organizar el trabajo, la forma de obtener una ahora se ve así (observa que DispatchQueueAttributeses un OptionSet, por lo que usas literales de estilo 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")
        }
    }
}

¿ Utilizas dispatch_afterpara trabajar más tarde? Este también es un método para colas, y se necesita un DispatchTime, que tiene operadores para varios tipos numéricos, por lo que puedes 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 de Dispatch abriendo su interfaz en Xcode 8: use Abrir rápidamente para encontrar el módulo de Dispatch, o coloque un símbolo (como DispatchQueue) en su proyecto/área de juegos Swift y haga clic con el botón Comando en él, luego explore el módulo desde allí. (Puede encontrar la API Swift Dispatch en el nuevo y elegante sitio web de referencia de API de Apple y en el visor de documentos en Xcode, pero parece que el contenido del documento de la versión C aún no se ha trasladado).

Consulte la Guía de migración para obtener más consejos.

rickster avatar Jun 14 '2016 00:06 rickster

En Xcode 8 beta 4 no funciona...

Usar:

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")
})
ingconti avatar Aug 13 '2016 08:08 ingconti

Este es un buen ejemplo de Swift 4aproximadamente async:

DispatchQueue.global(qos: .background).async {
    // Background Thread
    DispatchQueue.main.async {
        // Run UI Updates or call completion block
    }
}
S. Matsepura avatar Mar 01 '2017 12:03 S. Matsepura

en Xcode 8 uso:

DispatchQueue.global(qos: .userInitiated).async { }
Marco avatar Oct 09 '2016 16:10 Marco