Así que recientemente volví a Swift e iOS después de una pausa y me encontré con un problema con la ejecución asincrónica. Estoy usando el SDK de iOS de Giphy para ahorrarme mucho trabajo, pero su documentación es prácticamente inexistente, por lo que no estoy seguro de lo que podría estar pasando bajo el capó en su función que llama a su API.

Llamo a mi función que contiene el código siguiente desde el constructor de un objeto estático (no creo que ese sea el problema, ya que también intenté llamarlo desde un método cellForItemAt para una Vista de colección).

Mi problema es que mi función regresa y la ejecución continúa antes de que finalice la llamada API. He intentado utilizar DispatchQueue.main.async y eliminar Dispatch por completo, y DispatchGroups, en vano. Lo único que funcionó fue un semáforo, pero creo recordar haber leído que no era la mejor práctica.

Cualquier consejo sería genial, he estado atrapado en esto durante muuuuucho demasiado. Muchas gracias de antemano

GiphyCore.shared.gifByID(id) { (response, error) in
        if let media = response?.data {
            DispatchQueue.main.sync {
                print(media)
                ret = media
            }
        }
    }

return ret
0
Gus 14 abr. 2020 a las 22:35

2 respuestas

Mi problema es que mi función regresa y la ejecución continúa antes de que finalice la llamada API.

Ese es el objetivo de las llamadas asincrónicas. Una llamada de red puede tomar una cantidad arbitraria de tiempo, por lo que inicia la solicitud en segundo plano y le indica cuándo finalizó.

En lugar de devolver un valor de su código, tome un parámetro de devolución de llamada y llámelo cuando sepa que la llamada Giphy ha finalizado. O use una biblioteca de promesas. O el patrón delegado.

Lo único que funcionó fue un semáforo, pero creo recordar haber leído que no era la mejor práctica.

No hagas esto. Bloqueará su IU hasta que se complete la llamada de red. Como no sabe cuánto tiempo tomará, su interfaz de usuario no responderá durante un período de tiempo desconocido. Los usuarios pensarán que su aplicación se ha bloqueado en conexiones lentas.

3
Jim 14 abr. 2020 a las 19:42

Simplemente puede agregar esto dentro de un método y usar un controlador de finalización y, por lo tanto, no necesita esperar la respuesta. Podrías hacerlo así:

func functionName(completion: @escaping (YOURDATATYPE) -> Void) {
    GiphyCore.shared.gifByID(id) { (response, error) in
        if let media = response?.data {
            completion(media)
            return
        }
    }
}

Llama a tu método así

functionName() { response in
    DispatchQueue.main.async {
        // UPDATE the UI here
    }
}
-1
Edwin Lileo 14 abr. 2020 a las 19:48