My app will need to download files from my website from several different places in the app, so it seems to make sense to write the function to accomplish the download once, put it in its own class, and call that function from each ViewController. So far, so good, things work. The download is happening, and the downloaded file will print
correctly.
The problem comes when the download function goes to send a "success" or "failed" message back to the ViewController that called it, so that the VC can then react accordingly -- update the display, close out the download dialog, whatever. How to make that happen is where I'm stuck.
What I have:
Each of ViewControllerTwo and ViewControllerThree (which are identical for now, other than requesting different files from my server) calls the download function thus:
Downloader.load(url: urlForFileA!, to: localDestinationFileA, callingViewControllerNumber: 2)
The code for the downloader function (which is currently synchronous, but will eventually become asynchronous) looks like this (in its own Downloader
class):
class func load(url: URL, to localUrl: URL, callingViewControllerNumber: Int) {
let sessionConfig = URLSessionConfiguration.default
let session = URLSession(configuration: sessionConfig)
let request = URLRequest(url: url, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData)
let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
if let tempLocalUrl = tempLocalUrl, error == nil {
// Got a file, might be a 404 page...
if let statusCode = (response as? HTTPURLResponse)?.statusCode {
print("Success downloading: \(statusCode)")
if statusCode == 404 {
// ERROR -- FILE NOT FOUND ON SERVER
returnToCaller(sourceIdent: callingViewControllerNumber, successStatus: .fileNotFound, errorMessage: "File not Found, 404 error")
}
}
do {
try FileManager.default.copyItem(at: tempLocalUrl, to: localUrl)
// SUCCESS!
returnToCaller(sourceIdent: callingViewControllerNumber, successStatus: .success, errorMessage: "")
} catch (let writeError) {
returnToCaller(sourceIdent: callingViewControllerNumber, successStatus: .movingError, errorMessage: "\(writeError)")
}
} else {
returnToCaller(sourceIdent: callingViewControllerNumber, successStatus: .downloadFailed, errorMessage: "Grave Unexplained Failure")
}
}
task.resume()
}
This part works.
The returnToCaller
function is an admittedly ugly (okay, very, very ugly) way to send something back to the calling ViewController:
class func returnToCaller(sourceIdent : Int, successStatus : downloadSuccessStatusEnum, errorMessage : String) {
switch sourceIdent {
case 2:
ViewControllerTwo().returnFromDownload(successStatus: successStatus, errorMessage: errorMessage)
case 3:
ViewControllerThree().returnFromDownload(successStatus: successStatus, errorMessage: errorMessage)
default:
fatalError("Unknown sourceIdent of \(sourceIdent) passed to func returnToCaller")
}
}
The problem is that when that returnFromDownload
function in the original ViewController is called, it isn't aware of anything in the VC that's loaded -- I go to change the background color of a label, and get a runtime error that the label is nil
. The label exists, but this call into the ViewController code is happening in isolation from the running, instantiated VC itself. (Probably the wrong vocabulary there -- apologies.) The code runs and can print
but errors out when interacting with anything in the View itself.
The more I work with this, the less confident I am that I'm on the right track here, and my limited experience with Swift isn't enough to see what needs to be happening so that the download function can do all its work "over here" and then return a success/failure message to the calling VC so that the VC can then work with it.
This question seems to be asking something similar; the one answer there doesn't address my (nor, I think, his) root question of how to get code within the presented VC running again with the results of what happened outside the VC (manager approval in his case, download in mine).
Not asking for my code to be rewritten (unless it's a quick fix), but needing to be pointed in the right direction. Many thanks!