pods library eureka custom best awesome ios swift asynchronous

ios - library - Espere a que se complete la operación asíncrona en Swift



swift libraries (3)

Detalles

Xcode 9.2, Swift 4

Solución

class AsyncOperation { private let semaphore: DispatchSemaphore private let dispatchQueue: DispatchQueue typealias CompleteClosure = ()->() init(numberOfSimultaneousActions: Int, dispatchQueueLabel: String) { semaphore = DispatchSemaphore(value: numberOfSimultaneousActions) dispatchQueue = DispatchQueue(label: dispatchQueueLabel) } func run(closure: @escaping (@escaping CompleteClosure)->()) { dispatchQueue.async { self.semaphore.wait() closure { self.semaphore.signal() } } } }

Uso

let asyncOperation = AsyncOperation(numberOfSimultaneousActions: 1, dispatchQueueLabel: "AnyString") asyncOperation.run { completeClosure in // sync/async action // ... // action complete completeClosure() }

Muestra completa

import UIKit class ViewController: UIViewController { let asyncOperation = AsyncOperation(numberOfSimultaneousActions: 1, dispatchQueueLabel: "AnyString") var counter = 1 override func viewDidLoad() { super.viewDidLoad() let button = UIButton(frame: CGRect(x: 50, y: 50, width: 100, height: 40)) button.setTitle("Button", for: .normal) button.setTitleColor(.blue, for: .normal) button.addTarget(self, action: #selector(buttonTapped), for: .touchUpInside) view.addSubview(button) } @objc func buttonTapped() { print("Button tapped at: /(Date())") asyncOperation.run { completeClosure in let counter = self.counter print(" - Action /(counter) strat at /(Date())") self.counter += 1 DispatchQueue.global(qos: .background).async { sleep(1) print(" - Action /(counter) end at /(Date())") completeClosure() } } } }

Resultados

No estoy seguro de cómo manejar esta situación, ya que soy muy nuevo en el desarrollo de iOS y Swift. Estoy realizando la obtención de datos como así:

func application(application: UIApplication!, performFetchWithCompletionHandler completionHandler: ((UIBackgroundFetchResult) -> Void)!) { loadShows() completionHandler(UIBackgroundFetchResult.NewData) println("Background Fetch Complete") }

Mi función loadShows () analiza un montón de datos que obtiene de un sitio web cargado en un UIWebView. El problema es que tengo un temporizador que espera aproximadamente 10 segundos en la función loadShows. Esto permite que el javascript en la página se cargue por completo antes de comenzar a analizar los datos. Mi problema es que el controlador de finalización se completa antes de que lo haga mi loadShows ().

Lo que me gustaría hacer es agregar un bool para "isCompletedParsingShows" y hacer que la línea completadaHandler espere hasta que ese bool sea verdadero. ¿Cuál es la mejor manera de manejar esto?


dos formas de resolver esto, ambas usan Grand Central Dispatch (que es similar en Swift y Objective C):

  1. cambie el método loadShows para hacerlo sincrónico y use la misma cola de envío que el programa FinalizaciónHandler , luego envuelva todo el cuerpo del método en dispatch_async ; De esta manera, la llamada al método finaliza de inmediato, pero se llamará a completedHandler después de loadShows si se termina, como en un programa síncrono

  2. use un semáforo GCD, como el BOOL que menciona, pero creado con dispatch_semaphore_create ; llama a dispatch_semaphore_wait antes de completarHandler para que espere a que se desbloquee el semáforo (desbloquéelo con dispatch_semaphore_signal ); recuerde colocar el cuerpo de su método dentro de una llamada dispatch_async para no tener que bloquear el resto de la aplicación mientras espera a que se complete loadShows.


tienes que pasar tu función asíncrona al controlador para llamar más tarde:

func application(application: UIApplication!, performFetchWithCompletionHandler completionHandler: ((UIBackgroundFetchResult) -> Void)!) { loadShows(completionHandler) } func loadShows(completionHandler: ((UIBackgroundFetchResult) -> Void)!) { //.... //DO IT //.... completionHandler(UIBackgroundFetchResult.NewData) println("Background Fetch Complete") }

O (forma más limpia IMHO)

añadir una finalización intermediaHandler

func application(application: UIApplication!, performFetchWithCompletionHandler completionHandler: ((UIBackgroundFetchResult) -> Void)!) { loadShows() { completionHandler(UIBackgroundFetchResult.NewData) println("Background Fetch Complete") } } func loadShows(completionHandler: (() -> Void)!) { //.... //DO IT //.... completionHandler() }