Last active
October 24, 2019 14:20
-
-
Save strzempa/4cc3181ff86f5527ab4e451697477c2f to your computer and use it in GitHub Desktop.
Purpose of this service is synchronizing an urlSession delegate to have result accessible in single method where we pass a remote url and retreive a local url in closure.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import Foundation | |
protocol FileService { | |
var observation: Any? { get set } | |
var session: URLSession { get set } | |
var fileManager: FileManager { get set } | |
func fetchAndSaveLocally(url: URL, _ completion: @escaping (_ result: Result<URL, ServiceError>) -> Void) | |
} | |
final class DefaultFileService: NSObject, FileService { | |
var observation: Any? | |
lazy var session: URLSession = URLSession(configuration: .default, delegate: self, delegateQueue: operationQueue) | |
lazy var fileManager: FileManager = FileManager.default | |
@objc private dynamic var pdfURL: URL? | |
private var error: Error? | |
private lazy var operationQueue: OperationQueue = OperationQueue() | |
func fetchAndSaveLocally(url: URL, _ completion: @escaping (_ result: Result<URL, ServiceError>) -> Void) { | |
let observationHandlerTask = observationHandler() | |
let fetchHandlerTask = fetchHandler(session: session) | |
observation = observe(\.pdfURL, options: [.new], changeHandler: { fileService, _ in | |
observationHandlerTask(fileService, completion) | |
}) | |
fetchHandlerTask(url) | |
} | |
} | |
private extension DefaultFileService { | |
func fetchHandler(session: URLSession) -> (_ url: URL) -> Void { | |
return { url in | |
session.downloadTask(with: url).resume() | |
} | |
} | |
typealias ObservationHandlerBlock = (_ fileService: DefaultFileService, _ completion: @escaping (_ result: Result<URL, ServiceError>) -> Void) -> Void | |
func observationHandler() -> ObservationHandlerBlock { | |
return { fileService, completion in | |
guard let pdfURL = fileService.pdfURL else { | |
completion(.failure(ServiceError.fetchingFailure("no pdfURL saved, possible error \(fileService.error?.localizedDescription ?? "")"))) | |
return | |
} | |
completion(.success(pdfURL)) | |
} | |
} | |
} | |
extension DefaultFileService: URLSessionDownloadDelegate { | |
func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) { | |
/// create destination URL with the original file name | |
guard let url = downloadTask.originalRequest?.url else { | |
self.pdfURL = nil | |
self.error = ServiceError.noExpectedData("downloadTask.originalRequest.url not retreived") | |
return | |
} | |
let documentsPath = fileManager.urls(for: .cachesDirectory, in: .userDomainMask)[0] | |
let destinationURL = documentsPath.appendingPathComponent(url.lastPathComponent) | |
/// delete original copy | |
try? FileManager.default.removeItem(at: destinationURL) | |
/// copy from temp to Document | |
do { | |
try FileManager.default.copyItem(at: location, to: destinationURL) | |
self.pdfURL = destinationURL | |
} catch let error { | |
self.pdfURL = nil | |
self.error = error | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment