Cómo limitar simultáneas en vivo URLSessions con Combinar?

0

Pregunta

Tengo un montón (~200) direcciones url de las imágenes, y necesito descargar de cada uno, entonces el proceso (cambiar el tamaño), luego de la actualización de la memoria caché. La cosa es que solo me quiere para tener en un máximo de 3 solicitudes a la vez, y dado que las imágenes son pesadas, yo también no quiero un montón de respuestas de "colgar" en espera de ser procesados (y teniendo memoria...).

TLDR quiero llamar a la siguiente (4º) solicitud de red sólo después de que el receiveValue en el sink se llama en uno de los primeros 3 pedidos... (es decir, después de la respuesta de la red y procesamiento son de hecho...).

Será este flujo de trabajo, y se aferran a la espera de la url y no caer en el piso?

También necesito que buffer() llame? Yo lo uso después de ver esta respuesta: https://stackoverflow.com/a/67011837/2242359

wayTooManyURLsToHandleAtOnce // this is a `[URL]`
    .publisher
    .buffer(size: .max, prefetch: .byRequest, whenFull: .dropNewest) // NEEDED?
    .flatMap(maxPublishers: .max(3)) { url in
       URLSession.shared
           .dataTaskPublisher(for: url)
           .map { (data: Data, _) -> Picture in
               Picture(from: data)
           }
    }
    .tryCompactMap {
        resizeImage(picture: $0) // takes a while and might fail
    }
    .receive(on: DispatchQueue.main)
    .sink { completion
        // handling completion... 
    } receiveValue: { resizedImage
        self.cache.append(resizedImage)
    }
    .store(...)
combine swift urlsession
2021-11-23 22:14:45
1

Mejor respuesta

0

Me gustaría utilizar un tema. Esta no es una solución óptima, pero se ve de trabajo y tal vez va a desencadenar otras ideas

var cancellable: AnyCancellable?

var urls: [String] = (0...6).map { _ in "http://httpbin.org/delay/" + String((0...2).randomElement()!) }

var subject: PassthroughSubject<[String], Never> = .init()

let maxConcurrentRequests = 3

override func viewDidAppear(_ animated: Bool) {
    super.viewDidAppear(animated)
    
    print(urls)
    
    cancellable = subject
        .flatMap({ urls -> AnyPublisher<[URLSession.DataTaskPublisher.Output], URLError> in
            let requests = urls.map { URLSession.shared.dataTaskPublisher(for: URL.init(string: $0)!) }
            return Publishers.MergeMany(requests)
                .collect().eraseToAnyPublisher()
        })
        .print()
        .sink(receiveCompletion: { completion in
            print(completion)
        }, receiveValue: { value in
            print(value)
            if self.urls.count <= self.maxConcurrentRequests {
                self.urls.removeAll()
                self.subject.send(completion: .finished)
            } else {
                self.urls.removeLast(self.maxConcurrentRequests)
                self.subject.send(self.urls.suffix(self.maxConcurrentRequests))
            }
        })
    
    subject.send(urls.suffix(maxConcurrentRequests))
}
2021-11-24 11:30:11

No llamar self.subject.send(completion: .finished) en el lavabo de terminar mi suscripción para siempre? (es decir, ignorando el futuro de los valores emitidos)
Aviel Gross

@AvielGross sí, Sí. Según tengo entendido, su colección de url que se crea una sola vez por la vista controlador / rechazar. Si no es cierto entonces no enviar ".terminado", pero tiene un gatillo como didSet en la url de la matriz o de otra para relanzar con el tema.enviar después de vaciar la matriz y volver a llenar.
Blazej SLEBODA

En otros idiomas

Esta página está en otros idiomas

Русский
..................................................................................................................
Italiano
..................................................................................................................
Polski
..................................................................................................................
Română
..................................................................................................................
한국어
..................................................................................................................
हिन्दी
..................................................................................................................
Français
..................................................................................................................
Türk
..................................................................................................................
Česk
..................................................................................................................
Português
..................................................................................................................
ไทย
..................................................................................................................
中文
..................................................................................................................
Slovenský
..................................................................................................................