From d6a42540c45fc96e0c89e476d8ba98603e036c89 Mon Sep 17 00:00:00 2001 From: Darren Ford Date: Tue, 26 Apr 2022 17:27:09 +1000 Subject: [PATCH] Support multithreaded downloads for RemoteData All posters for a search selection are downloaded before the first one is shown in the UI. For popular tv series, there can be 20 or more posters for the series which are all downloaded before the 'first' poster appears in the UI. Currently, the posters are downloaded serially which means that on a slow-ish connection to tvDB (for eg) this can take quite a while before the 'first' poster appears in the UI. This patch moves patch downloading onto the global 'utility' thread which allows for multiple simultaneous downloads, limiting the number of simultaneous downloads to 10. --- Framework/src/RemoteData.swift | 43 +++++++++++++++++++--------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/Framework/src/RemoteData.swift b/Framework/src/RemoteData.swift index 1a0c7f6..8fd6099 100644 --- a/Framework/src/RemoteData.swift +++ b/Framework/src/RemoteData.swift @@ -7,28 +7,27 @@ import Foundation -fileprivate class RemoteCaching { - // Used a session that caches its results - static let remoteLoadSession: URLSession = { - // Create URL Session Configuration - let configuration = URLSessionConfiguration.default.copy() as! URLSessionConfiguration +// Limit the number of simultaneous downloads +private let RemoteDownloadLimiter = DispatchSemaphore(value: 10) - // Set the in-memory cache to 128 MB - let cache = URLCache() - cache.memoryCapacity = 128 * 1024 * 1024 - configuration.urlCache = cache +// A URLSession that caches its results +private let RemoteLoadSession: URLSession = { + // Create URL Session Configuration + let configuration = URLSessionConfiguration.default.copy() as! URLSessionConfiguration - // Define Request Cache Policy - configuration.requestCachePolicy = .useProtocolCachePolicy - configuration.urlCache = cache + // Set the in-memory cache to 128 MB + let cache = URLCache() + cache.memoryCapacity = 128 * 1024 * 1024 + configuration.urlCache = cache - return URLSession(configuration: configuration) - }() -} + // Define Request Cache Policy + configuration.requestCachePolicy = .useProtocolCachePolicy + configuration.urlCache = cache + + return URLSession(configuration: configuration) +}() @objc public class RemoteData : NSObject { - private static let queue = DispatchQueue(label: "io.metaz.RemoteDataQueue") - public let url : URL public let expectedMimeType : String @@ -110,13 +109,19 @@ fileprivate class RemoteCaching { let url = self.data!.url let expectedMimeType = self.data!.expectedMimeType - RemoteData.queue.async { + + DispatchQueue.global(qos: .utility).async { + RemoteDownloadLimiter.wait() + defer { + RemoteDownloadLimiter.signal() + } + var downloadData : Data?, responseError : NSError? let signal = DispatchSemaphore(value: 0) if self.data == nil { return; } - RemoteCaching.remoteLoadSession.dataTask(with: url) { (d, resp, err) in + RemoteLoadSession.dataTask(with: url) { (d, resp, err) in if let error = err { let info = [NSLocalizedDescriptionKey: error.localizedDescription] let statusCode = (resp as? HTTPURLResponse)?.statusCode ?? 0