Comment limiter simultanées vivre URLSessions avec les Combiner?

0

La question

J'ai beaucoup (~200) url pour les images, et j'ai besoin de télécharger chacun, alors le processus (redimensionner), puis mettre à jour le cache. La chose est - je ne veux avoir au max 3 demandes à la fois, et puisque les images sont lourdes, je ne veux pas beaucoup de réponses "suspendu" en attente de traitement (et de prendre de la mémoire...).

TLDR, je tiens à appeler l'autre (4e) réseau demande qu'après l' receiveValue dans le sink est appelée sur l'une des 3 premières demandes... (c'est à dire après le réseau de réponse et de traitement sont à la fois faire...).

Sera-ce des flux de travail, et il va tenir à l'attente des url et ne pas les laisser tomber sur le sol?

Aussi ai-je besoin que buffer() appel? Je l'utilise après avoir vu cette réponse: 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

La meilleure réponse

0

Je voudrais utiliser un objet. Ce n'est pas une solution optimale, mais il semble de travail et peut-être déclencher d'autres idées

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

Ne pas appeler self.subject.send(completion: .finished) sur l'évier de la fin de mon abonnement pour toujours? (c'est à dire en ignorant les valeurs futures émise)
Aviel Gross

@AvielGross Oui, c'est fait. J'ai compris que votre collection d'url créés une fois par vue-contrôleur présent / rejeter. Si ce n'est pas vrai, alors ne pas envoyer ".terminé" mais vous avez un déclencheur comme didSet sur les url tableau ou d'un autre de relancer avec le sujet.envoyer après la vidange de la matrice et de le remplir.
Blazej SLEBODA

Dans d'autres langues

Cette page est dans d'autres langues

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