Per limitare la concorrente diretta URLSessions con Combine?

0

Domanda

Ho un sacco (~200) gli url per le immagini, e ho bisogno di scaricare ogni uno, poi il processo (ridimensionare), quindi aggiornare la cache. Il fatto è che - voglio solo avere al max 3 richieste in una sola volta, e dato che le immagini sono pesanti, anche io non voglio un sacco di risposte "sospesa" in attesa di essere processato (e l'assunzione di memoria...).

TLDR voglio chiamare la prossima (4) richiesta di rete solo dopo il receiveValue nel sink è chiamato uno dei primi 3 richieste... (cioè dopo la risposta della rete & l'elaborazione sono sia fatto...).

Questo flusso di lavoro, e potrà contenere l'attesa url e non farli cadere sul pavimento?

Inoltre ho bisogno che buffer() chiamata? Io lo uso dopo aver visto questa risposta: 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

Migliore risposta

0

Vorrei usare un oggetto. Questa non è una soluzione ottimale, ma cerca di lavoro e forse anche attivare altre idee

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

Non chiamare self.subject.send(completion: .finished) sul lavandino fine il mio abbonamento per sempre? (ie ignorando i valori futuri emessa)
Aviel Gross

@AvielGross Sì, lo fa. Ho capito che la tua collezione di url creato una volta per view controller / chiudere. Se non è vero allora non inviare ".finito", ma non si dispone di un trigger come didSet su url array o un altro a rilanciare con il soggetto.invia dopo aver svuotato la matrice e il rifornimento esso.
Blazej SLEBODA

In altre lingue

Questa pagina è in altre lingue

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