Swift 3.0: How to open a PDF in a different view controller when finished downloading using URLSessionDownloadDelegate
<p>In an app I'm writing, I need to download a PDF from a server and display it in a UIWebView. To this end, I've got a bit of code that retrieves the PDF from an endpoint (it's not a URL, and on a desktop computer, opens up a dialogue for saving as in a browser) and loads it onto the device by grabbing the data in a class called PDFGrabber:</p>

<pre><code>func getPDF(completionHandler:@escaping (URL) -&gt; Void)
{
    let theURL:String = "https://mywebsite.com/Endpoint"
    let fileURL:URL = URL(string: theURL)!
    var request = URLRequest(url: fileURL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)
    let session = URLSession.shared

    let task = session.dataTask(with: request, completionHandler: {data, response, error -&gt; Void in

    var documentURL = (FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)).last
    documentURL = documentURL?.appendingPathComponent("MyDocument.pdf")

    do
    {
        try data?.write(to: documentURL!, options: .atomic)
        completionHandler(documentURL!)
        }
        catch
        {
            print(error)
        }
    })

    task.resume()
}
</code></pre>

<p>Then, in the table view controller showing the PDFs (let's call it PDFTableView, I can use the documentURL from the PDFGrabber when a PDF is requested (by tapping a cell in the table):</p>

<pre><code>PDFGrabber.getPDF(){fileURL -&gt; () in
    DispatchQueue.main.async
    {
        if let resultController = self.storyboard!.instantiateViewController(withIdentifier: "PDFViewer") as? PDFViewer 
        {
            resultController.thePDFPath = stringURL
            self.present(resultController, animated: true, completion: nil)
        }
    }
</code></pre>

<p>Finally, I have another View Controller with a UIWebView called "WebView" and the attribute "thePDFPath" as a string in the PDFViewer view controller. In the viewDidLoad() method, I can say:</p>

<pre><code>override func viewDidLoad()
{
    let pathToPDF:URL = URL(string: thePDFPath)!
    WebView.loadRequest(URLRequest(url: pathToPDF))
}
</code></pre>

<p>Together, this loads the PDF into the web view. However, the loading times can be a little slow, and I'd like to be able to calculate how much of the PDF has been loaded onto a user's device using a progress bar and a string. From other questions, I gather than I'd need to have my PDFGrabber class extend URLSessionDownloadDelegate, and then implement the functions. To get the amount of bytes downloaded is straightforward, since I can simply go:</p>

<pre><code>func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten writ: Int64, totalBytesExpectedToWrite exp: Int64)
{
    percentDownloaded = (Float(writ)/Float(exp)) * 100
    print("Progress: " + String(describing: percentDownloaded))
}
</code></pre>

<p><strong>But I'd also like to be able to open the PDFView only after the PDF is wholly downloaded after displaying its progress as a percent</strong> (I've got an overlay view that does this). Before, I could use a completion handler and wait until the PDF finished downloading, then open it.</p>

<p>However, this method does not allow me to access the amount of bytes downloaded; would I go about opening the view from the </p>

<pre><code>urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL)
</code></pre>

<p>function, or is there something else I need to do?</p>

<p>Suggestions would be much appreciated; thanks! </p>