是否可以使用 URL 会话委托方法进行进度和完成处理程序来完成?还是更好的选择?

Posted

技术标签:

【中文标题】是否可以使用 URL 会话委托方法进行进度和完成处理程序来完成?还是更好的选择?【英文标题】:Is it possible to use URL session delegate method for progress and completion handler for completion? Or better option? 【发布时间】:2020-04-20 05:23:32 【问题描述】:

我正在使用我的下载器类通过 URLSession 委托方法下载文件,并使用委托方法的进度更新进度条。我从我的视图中这样调用下载类:

downloader.download(url: self.video.url, fileName: self.video.filePath)

完成后,我想更新视图中的一些变量以停止显示进度条。我正在考虑使用完成处理程序,但我认为这在使用委托进行进度和完成时不会真正起作用。而且我无法在下载器的完成委托方法中访问要更新的视图变量。

我想知道是否可以使用委托方法进行进度更新并使用完成处理程序来完成?这可能吗?

你有什么想法我可以做到吗?

这是我的下载器类:

class download: NSObject, URLSessionDelegate, URLSessionDownloadDelegate

    @ObservedObject var globalScrollTitle: ScrollTitle = ScrollTitle.sharedInstance

    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)

        let progress = Float(totalBytesWritten) / Float(totalBytesExpectedToWrite)
        DispatchQueue.main.async(execute: 
            self.globalScrollTitle.mainprogress = CGFloat(progress)
            print(self.globalScrollTitle.mainprogress)
        )
    

    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) 
        // check for and handle errors:
        // * downloadTask.response should be an HTTPURLResponse with statusCode in 200..<299
        print("download complete!")

        do
            let downloadedData = try Data(contentsOf: location)

            DispatchQueue.main.async(execute: 
                print("transfer completion OK!")

                let documentDirectoryPath = NSSearchPathForDirectoriesInDomains(.downloadsDirectory, .userDomainMask, true).first! as NSString
                let destinationPath = documentDirectoryPath.appendingPathComponent((downloadTask.response?.suggestedFilename)!)

                let pdfFileURL = URL(fileURLWithPath: destinationPath)
                FileManager.default.createFile(atPath: pdfFileURL.path,
                                               contents: downloadedData,
                                               attributes: nil)

                if FileManager.default.fileExists(atPath: pdfFileURL.path) 
                    print("file present!") // Confirm that the file is here!
                
            )
         catch 
            print (error.localizedDescription)
        


    

    func download(url: String, fileName: String) 
        let myUrl = URL(string: url)
        let request = URLRequest(url:myUrl!)
        //let config = URLSessionConfiguration.default
        //let operationQueue = OperationQueue()
        let session = URLSession(configuration: .default, delegate: self, delegateQueue: nil)
        let downloadTask = session.downloadTask(with: request)
        downloadTask.resume()
        //completion()
    

【问题讨论】:

这能回答你的问题吗? get progress from dataTaskWithURL in swift 感谢您的帮助!我设法使用该链接找到了答案。 【参考方案1】:

感谢 Faysal Ahmed,我设法找到了以下可行的解决方案。这让我可以在使用完成处理程序的同时跟踪更新 UI 的进度。

    observation = task.progress.observe(\.fractionCompleted)  progress, _ in
        DispatchQueue.main.async(execute: 
            self.globalScrollTitle.mainprogress = CGFloat(progress.fractionCompleted)
        )
        if progress.fractionCompleted == 1 
            completion()
        
    

我的下载函数现在看起来像这样:

func download(url: String, fileName: String, completion: @escaping () -> Void) 
        let myUrl = URL(string: url)
        let request = URLRequest(url:myUrl!)
        let config = URLSessionConfiguration.default
        let operationQueue = OperationQueue()
        let session = URLSession(configuration: config, delegate: nil, delegateQueue: operationQueue)

        let task = session.dataTask(with: request)  (data, response, error) in
            guard error == nil else 
                print(error!)
                return
            
            // Success
            if let statusCode = (response as? HTTPURLResponse)?.statusCode 
                print("Success: \(statusCode)")
            

            do 
                let documentFolderURL = try FileManager.default.url(for: .downloadsDirectory, in: .userDomainMask, appropriateFor: nil, create: false)
                let fileURL = documentFolderURL.appendingPathComponent(fileName)
                try data!.write(to: fileURL)

                DispatchQueue.main.async 

                    if FileManager.default.fileExists(atPath: fileURL.path) 
                        print("file present!") // Confirm that the file is here!
                    
                

             catch  
                print("error writing file \(error)")
            
        

        observation = task.progress.observe(\.fractionCompleted)  progress, _ in
            DispatchQueue.main.async(execute: 
                self.globalScrollTitle.mainprogress = CGFloat(progress.fractionCompleted)
            )
            if progress.fractionCompleted == 1 
                completion()
            
        

        task.resume()
    

【讨论】:

以上是关于是否可以使用 URL 会话委托方法进行进度和完成处理程序来完成?还是更好的选择?的主要内容,如果未能解决你的问题,请参考以下文章

C# Winform 多线程异步委托进度条

.NET 请求被挂起,前端轮询,委托

访问ServletContextListener中的会话变量

如何在不重新加入会话的情况下检查屏幕会话的进度?

C#如何使用异步编程

如何以 Fire-And-Forget 的形式调用委托调用