Entonces, tengo datos complicados para buscar, que implican 4 solicitudes, cada una dependiendo del resultado de la última, y algunas de ellas devuelven una lista, por lo que para cada elemento de esa lista, tengo que obtener información.

Contexto

Estoy trabajando con la API de YouTube y los datos que tengo que obtener son una lista de los últimos videos enviados por los canales suscritos por el usuario.

Aquí están las solicitudes necesarias para hacer esto:

  • OBTENER / suscripciones / lista [1]

  • OBTENER / canales / lista [2]

  • GET / playlistItems / list [3]

  • OBTENER / videos [4]

[1]: devuelve una lista de los canales suscritos por el usuario. El tamaño de devolución está configurado en 5, por lo que tengo que repetir esta solicitud hasta que se hayan obtenido todos los canales suscritos

[2]: devuelve el ID de la lista de reproducción de videos enviados para un canal específico.

[3]: devuelve n últimos videos de un canal específico

[4]: devuelve información para un video específico

Primer intento

Al principio, obtuve los datos de forma síncrona, es decir, ejecuté la solicitud [1], hasta que se obtuvieron todos los canales. Luego, recorrí la lista de canales y, para cada canal, ejecuté la solicitud [2] para obtener la identificación de la lista de reproducción. Luego solicite [3] para obtener n videos, y para cada video, obtenga su información con la solicitud [4].

El problema

El problema con eso es que lleva mucho tiempo devolver los videos al usuario, así que pensé en ejecutar la solicitud en paralelo. El problema con eso es que necesito saber cuándo han terminado todas las solicitudes para que se ejecuten, para reordenar la lista de videos por fecha. Y para hacer eso, mi código se ha convertido en un complicado lío de DispatchGroup en todas partes.

Entonces, en resumen, ¿cuál es el mejor enfoque para tratar un problema como este, donde tengo varias solicitudes que dependen unas de otras , y me gustaría ejecutar algunas de ellos en paralelo (el segundo, que tengo que hacer para cada canal) y necesito saber cuándo han terminado.

0
Marcos Tanaka 13 feb. 2018 a las 23:57

2 respuestas

La mejor respuesta

Entonces, me estaba dando golpes de cabeza tratando de organizar este complejo proceso de solicitud usando NSURLSession, y no pude encontrar el código que quería.

Para facilitar el trabajo, utilicé Just, lo que me permitió ejecutar estas solicitudes en un forma más sencilla, clara y sencilla.

Otra opción sería envolver NSURLSession en una promesa usando PromiseKit, que permite fácilmente encadenamiento de solicitudes.

0
Marcos Tanaka 16 feb. 2018 a las 18:53

Utilice DispatchGroup. DispatchGroup es un "componente" en iOS que puede agrupar algunas operaciones relacionadas, que se deben esperar.

Aquí no puedes usarlo directamente, ¿por qué? Debido a que la propia URLSession publica la operación web en un hilo de fondo diferente al iniciador, debemos enter y leave manualmente. Cuando el recuento de operaciones es 0, el group.wait regresa.

Este código no es el mejor patrón de diseño. Pero esto demuestra solo lo que se puede hacer en un patrón de diseño simple.

import UIKit

class URLRequestGroup {

    var dispatchGroup: DispatchGroup

    init(dispatchGroup: DispatchGroup) {
        self.dispatchGroup = dispatchGroup
    }

    init() {
        self.dispatchGroup = DispatchGroup()
    }

    func beginURLRequest(urlRequest: URLRequest,
                         completionHandler: @escaping (Data?, URLResponse?, Error?) -> ()) {

        let urlSession = URLSession(configuration: URLSessionConfiguration.default)
        // Enter the dispatchGroup manually
        dispatchGroup.enter()
        urlSession.dataTask(with: urlRequest, completionHandler: { [weak self] data, urlResponse, error in

            completionHandler(data, urlResponse, error)
            // Leave this dispatchGroup.
            self?.dispatchGroup.leave()
        }).resume()

    }

}

let group = URLRequestGroup()
group.beginURLRequest(urlRequest: URLRequest(url: URL(fileURLWithPath: "http://www.example.com")), completionHandler: { data, urlResponse, error in

    print(data?.count ?? 0)
})
// Put any other request here.
group.dispatchGroup.wait()
0
user9335240 13 feb. 2018 a las 21:19