0

All value in variable (filename, destinationFolder) is different for all loop except the "let uploadDidFinish: (()-> Void)". From what I learnt, it is supposed to be different as it is declared in a different instance.

I put the following code in view controller viewdidload()

let uploadDidFinish: ()-> Void = {
    print("\nunzip \(self.foldername+".zip")\n")
    self.c.unzipFile(foldername: self.mfoldername+"/"+self.foldername,filename: self.foldername+".zip")
}
DownloadManager.shared.downloadFile("https://ping.passivealtitude.com/magazinefile/"+foldername+"/"+foldername+".zip", to: mfoldername+"/"+foldername, filename: foldername+".zip", upload: uploadDidFinish)

After I loop 4 times, the result of code above is

downloaded to file:///Users/vivian/Library/Developer/CoreSimulator/Devices/3FF96128-FC8F-4D44-9B4D-DC1989EFF9FF/data/Containers/Data/Application/15B32C21-6117-4CD9-A70E-7C0BFC0DFA6A/Documents/Magazine/book1/book1.zip

downloaded to file:///Users/vivian/Library/Developer/CoreSimulator/Devices/3FF96128-FC8F-4D44-9B4D-DC1989EFF9FF/data/Containers/Data/Application/15B32C21-6117-4CD9-A70E-7C0BFC0DFA6A/Documents/Magazine/book2/book2.zip

downloaded to file:///Users/vivian/Library/Developer/CoreSimulator/Devices/3FF96128-FC8F-4D44-9B4D-DC1989EFF9FF/data/Containers/Data/Application/15B32C21-6117-4CD9-A70E-7C0BFC0DFA6A/Documents/Magazine/book3/book3.zip

downloaded to file:///Users/vivian/Library/Developer/CoreSimulator/Devices/3FF96128-FC8F-4D44-9B4D-DC1989EFF9FF/data/Containers/Data/Application/15B32C21-6117-4CD9-A70E-7C0BFC0DFA6A/Documents/Magazine/book4/book4.zip

unzip book4.zip

unzip book4.zip

unzip book4.zip

unzip book4.zip

when it supposed to be

unzip book1.zip

unzip book2.zip

unzip book3.zip

unzip book4.zip

First the function is passed to

class DownloadManager: NSObject {
...

@discardableResult
func downloadFile(_ url: String, to foldername: String, filename:String, upload: @escaping (()->Void)) -> DownloadOperation {
    let link = URL(string: url)
    let destinationFolder = createDirectory(foldername: foldername)
    let operation = DownloadOperation(session: session, url: link!, destinationFolder: destinationFolder, filename:filename, upload: upload)
    operations[operation.task.taskIdentifier] = operation
    queue.addOperation(operation)
    return operation
}

Then, I have passed the download file function to

class DownloadOperation : AsynchronousOperation {
    var task: URLSessionTask!
    let destinationFolder: URL
    let filename: String
    let uploadDidFinish: (()-> Void)
    let manager = FileManager.default

    init(session: URLSession, url: URL, destinationFolder: URL,filename: String, upload: @escaping (()->Void)) {
        self.filename = filename
        self.destinationFolder = destinationFolder
        self.uploadDidFinish = upload
        super.init()
        task = session.downloadTask(with: url)
    }

    override func cancel() {
        task.cancel()
        super.cancel()
    }

    override func main() {
        task.resume()
    }
}

extension DownloadOperation: URLSessionDownloadDelegate {

    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        do {
            let destinationURL = destinationFolder.appendingPathComponent(filename)
            if manager.fileExists(atPath: destinationURL.path) {
                try manager.removeItem(at: destinationURL)
            }
            try manager.moveItem(at: location, to: destinationURL)
            print(" \ndownloaded to \(destinationURL)\n")
        } catch {
            print("DownloadOperation: URLSessionDownloadDelegate: \(error)")
        }

        self.uploadDidFinish()

    }

The code below connects view controller to my download manager.

DispatchQueue.main.async {
            self.uploadDidFinish()
        }

The original code is from How To Download Multiple Files Sequentially using NSURLSession downloadTask in Swift

Why is the result same? Any help is much appreciated!

Shsgge
  • 13
  • 7
  • Where are you assigning the value to `folderName` in `DownloadManager.shared.downloadFile("https://ping.passivealtitude.com/magazinefile/"+foldername+"/"+foldername+".zip", to: mfoldername+"/"+foldername, filename: foldername+".zip", upload: uploadDidFinish)`? Share your code where you use the loop – Malik Aug 15 '17 at 06:32
  • In the first block, you can find this: DownloadManager.shared.downloadFile("https://ping.passivealtitude.com/magazinefile/"+foldername+"/"+foldername+".zip", to: mfoldername+"/"+foldername, filename: foldername+".zip", upload: uploadDidFinish), the foldername is the second parameter(to). I use this in parsing xml so the code is super long. The reason I know the foldername is correct because of the result. See updated result – Shsgge Aug 15 '17 at 06:39

2 Answers2

0

When uploadDidFinish been execute self.foldername already changed to book4, so print("\nunzip \(self.foldername+".zip")\n") always output: unzip book4.zip. e.g.

class DownloadOperation : AsynchronousOperation {
    ...    
    let uploadDidFinish: ((String, String)-> Void)
    init(session: URLSession, url: URL, destinationFolder: URL,filename: String, upload: @escaping ((String, String)->Void)) {
        ...       
        self.uploadDidFinish = upload
    }
}


extension DownloadOperation: URLSessionDownloadDelegate {
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
        ...
        self.uploadDidFinish(filename, destinationFolder.path)
    }
}
Zhang
  • 394
  • 2
  • 11
  • but they are in different class. Is there any way i produce the result i want? – Shsgge Aug 15 '17 at 07:37
  • @HuiWenYeoh YES, you can change you callback to get a what you want. wait for a minute I will write a demo for you. – Zhang Aug 15 '17 at 07:49
  • I tried to put it inside my loop but i cant separate download and call back because they are in the same method. I cant determine how long does one file take to download too. When I put both of them in asynafter, the filename has the same name. – Shsgge Aug 15 '17 at 08:10
  • hey I have found the solution! I have fixed it by removing @escaping. According to https://swiftunboxed.com/lang/closures-escaping-noescape-swift3/, >Asynchronous execution: If you execute the closure asynchronously on a dispatch queue, the queue will hold onto the closure for you. You have no idea when the closure will be executed and there’s no guarantee it will complete before the function returns. I guess "Asynchronous execution" is the reason. Thank you for your help!! – Shsgge Aug 15 '17 at 09:25
0

this is a typical error using asynchronous calls.when call back fires up, it uses the last value the string has..

ingconti
  • 10,876
  • 3
  • 61
  • 48