class FileUploaderManager:NSObject { static let shared = FileUploaderManager() fileprivate var operations = [Int: AsyncOperation]() lazy var session: URLSession = { let configuration = URLSessionConfiguration.background(withIdentifier: "bla bla bla") configuration.isDiscretionary = false configuration.sessionSendsLaunchEvents = true //configuration.shouldUseExtendedBackgroundIdleMode = false return URLSession(configuration: configuration, delegate: sessionDelegate, delegateQueue: nil) }() private let queue: OperationQueue = { let _queue = OperationQueue() _queue.maxConcurrentOperationCount = 1 return _queue }() var handlers:[String:(() -> Void)?] = [:] private override init() { super.init() } } extension FileUploaderManager { func addUploadable(content:FileContent) { DispatchQueue.global(qos: .background).async { self.prepare(content) } } private func prepare(_ content:FileContent) { let step1Operation = startOperation(content, session) let chunksOperation = chunksOperation(content, session, dependencies:step1Operation) let commit = lastOperation(content, client, dependencies:chunksOperation) } } extension FileUploaderManager { @discardableResult private func startOperation(_ content:FileContent,_ session:UrlSession) -> AsyncOperation { let operation = FirstOperation(...) queue.addOperation(operation) return operation } } extension FileUploaderManager { @discardableResult private func chunksOperation(_ content:FileContent,_ session:UrlSession _ dependencies:AsyncOperation?) -> [AsyncOperation] { var all:[AsyncOperation] = [] content.chunks.forEach { chunk in let operation = ChunkOperation(--) queue.addOperation(operation) all.append(operation) } return chunks } } extension FileUploaderManager { @discardableResult private func lastOperation(_ content:FileContent,_ session:UrlSession, _ dependencies:[AsyncOperation]?) -> AsyncOperation? { let last = LastOperation(....) dependencies?.forEach { op in last.addDependency(op) } queue.addOperation(last) return commit } } extension FileUploaderManager :URLSessionDataDelegate { func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {..} func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) {..} func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) {... } } extension FileUploaderManager: URLSessionDelegate { func urlSessionDidFinishEvents(forBackgroundURLSession session: URLSession) { DispatchQueue.main.async { [weak self] in guard let handler = app[session.configuration.identifier] else { return } handler?() } } }