【问题标题】:How to download file in swift?如何快速下载文件?
【发布时间】:2015-03-28 23:33:53
【问题描述】:

我刚开始从 android 学习适用于 iOS 的 Apple Swift 编程。我现在基本上可以阅读和操作 swift 代码,还学习了一些在 iOS swift 编程中使用的常用类,但仍然对语法和所有内容感到困惑。

我正在尝试下载文件。就像,让我们说来自这个网址

var url = "http://www.mywebsite.com/myfile.pdf"

单击按钮。也许还有视觉进步

通过在 stackoverflow 中搜索,我偶然发现了 Alamofire。我可能会尝试,但我不确定这是否是最适合我的方式。

所以,我想问一下我如何以及有哪些选择(iOS7 和 iOS8)来实现我的目标。此外,优点和缺点会很棒!

【问题讨论】:

    标签: ios swift file download


    【解决方案1】:

    没有 Alamofire 的示例下载器类:

    class Downloader {
        class func load(URL: NSURL) {
            let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
            let session = NSURLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
            let request = NSMutableURLRequest(URL: URL)
            request.HTTPMethod = "GET"
            let task = session.dataTaskWithRequest(request, completionHandler: { (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
                if (error == nil) {
                    // Success
                    let statusCode = (response as NSHTTPURLResponse).statusCode
                    println("Success: \(statusCode)")
    
                    // This is your file-variable:
                    // data
                }
                else {
                    // Failure
                    println("Failure: %@", error.localizedDescription);
                }
            })
            task.resume()
        }
    }
    

    这是在你自己的代码中使用它的方法:

    class Foo {
        func bar() {
            if var URL = NSURL(string: "http://www.mywebsite.com/myfile.pdf") {
                Downloader.load(URL)
            }
        }
    }
    

    Swift 3 版本

    还要注意将大文件下载到磁盘而不是内存中。参见`downloadTask:

    class Downloader {
        class func load(url: URL, to localUrl: URL, completion: @escaping () -> ()) {
            let sessionConfig = URLSessionConfiguration.default
            let session = URLSession(configuration: sessionConfig)
            let request = try! URLRequest(url: url, method: .get)
    
            let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
                if let tempLocalUrl = tempLocalUrl, error == nil {
                    // Success
                    if let statusCode = (response as? HTTPURLResponse)?.statusCode {
                        print("Success: \(statusCode)")
                    }
    
                    do {
                        try FileManager.default.copyItem(at: tempLocalUrl, to: localUrl)
                        completion()
                    } catch (let writeError) {
                        print("error writing file \(localUrl) : \(writeError)")
                    }
    
                } else {
                    print("Failure: %@", error?.localizedDescription);
                }
            }
            task.resume()
        }
    }
    

    【讨论】:

    • 嗨,德夫兰!我试过你的代码,它显示“成功:200”。我对代码还有一些其他问题: 1. 'Success: 200' 是否意味着文件已下载或 URL 有效? 2. 有没有办法在通知栏显示下载进度? 3. 设备中下载的文件在哪里(只用模拟器)?我需要检查文件是否存在。感谢您花时间回答我的问题。我也会按照您的建议检查 NSData
    • 1.从技术上讲,它意味着两者。成功 200 代表:对该 url 的请求已被接受,并且可以从服务器无错误地回答。 (200 是 OK 的 http 状态码)see: List of HTTP codes on Wikipedia
    • 2.对于这样的事情,我建议使用 Alamofire。在 Alamofire 的 github 页面上,有一个如何下载文件并返回当前进度的示例。它还可以帮助您编写更少的代码并获得相同的结果:) see: Downloading a File w/Progress.
    • 3.设备中下载的文件在哪里(仅使用模拟器)?我需要检查文件是否存在。您下载的文件可通过代码访问。您可以将其保存到磁盘或在内存中处理文件的内容。我的示例代码中的变量 data 包含整个 pdf 的二进制文件。要返回data的内容,就写println(data)要学习如何在ios上保存文件,看看:https://github.com/sketchytech/FileSave(还有一个swift版本)
    • 那么 url 和 localUrl 呢?
    【解决方案2】:

    Swift 4Swift 5 版本,如果还有人需要的话

    import Foundation
    
    class FileDownloader {
    
        static func loadFileSync(url: URL, completion: @escaping (String?, Error?) -> Void)
        {
            let documentsUrl = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    
            let destinationUrl = documentsUrl.appendingPathComponent(url.lastPathComponent)
    
            if FileManager().fileExists(atPath: destinationUrl.path)
            {
                print("File already exists [\(destinationUrl.path)]")
                completion(destinationUrl.path, nil)
            }
            else if let dataFromURL = NSData(contentsOf: url)
            {
                if dataFromURL.write(to: destinationUrl, atomically: true)
                {
                    print("file saved [\(destinationUrl.path)]")
                    completion(destinationUrl.path, nil)
                }
                else
                {
                    print("error saving file")
                    let error = NSError(domain:"Error saving file", code:1001, userInfo:nil)
                    completion(destinationUrl.path, error)
                }
            }
            else
            {
                let error = NSError(domain:"Error downloading file", code:1002, userInfo:nil)
                completion(destinationUrl.path, error)
            }
        }
    
        static func loadFileAsync(url: URL, completion: @escaping (String?, Error?) -> Void)
        {
            let documentsUrl =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    
            let destinationUrl = documentsUrl.appendingPathComponent(url.lastPathComponent)
    
            if FileManager().fileExists(atPath: destinationUrl.path)
            {
                print("File already exists [\(destinationUrl.path)]")
                completion(destinationUrl.path, nil)
            }
            else
            {
                let session = URLSession(configuration: URLSessionConfiguration.default, delegate: nil, delegateQueue: nil)
                var request = URLRequest(url: url)
                request.httpMethod = "GET"
                let task = session.dataTask(with: request, completionHandler:
                {
                    data, response, error in
                    if error == nil
                    {
                        if let response = response as? HTTPURLResponse
                        {
                            if response.statusCode == 200
                            {
                                if let data = data
                                {
                                    if let _ = try? data.write(to: destinationUrl, options: Data.WritingOptions.atomic)
                                    {
                                        completion(destinationUrl.path, error)
                                    }
                                    else
                                    {
                                        completion(destinationUrl.path, error)
                                    }
                                }
                                else
                                {
                                    completion(destinationUrl.path, error)
                                }
                            }
                        }
                    }
                    else
                    {
                        completion(destinationUrl.path, error)
                    }
                })
                task.resume()
            }
        }
    }
    

    这里是如何调用这个方法:-

    let url = URL(string: "http://www.filedownloader.com/mydemofile.pdf")
    FileDownloader.loadFileAsync(url: url!) { (path, error) in
        print("PDF File downloaded to : \(path!)")
    }
    

    【讨论】:

    • @BijenderSinghShekhawat 如何获取swift5中的下载百分比
    • 是的,有没有办法让它与百分比一起工作。我尝试添加 URLSessionDelegate 并添加 urlSession 函数来计算百分比,但它似乎不适用于此函数。
    【解决方案3】:

    这是一个展示如何进行同步和异步的示例。

    import Foundation
    
    class HttpDownloader {
    
        class func loadFileSync(url: NSURL, completion:(path:String, error:NSError!) -> Void) {
            let documentsUrl =  NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first as! NSURL
            let destinationUrl = documentsUrl.URLByAppendingPathComponent(url.lastPathComponent!)
            if NSFileManager().fileExistsAtPath(destinationUrl.path!) {
                println("file already exists [\(destinationUrl.path!)]")
                completion(path: destinationUrl.path!, error:nil)
            } else if let dataFromURL = NSData(contentsOfURL: url){
                if dataFromURL.writeToURL(destinationUrl, atomically: true) {
                    println("file saved [\(destinationUrl.path!)]")
                    completion(path: destinationUrl.path!, error:nil)
                } else {
                    println("error saving file")
                    let error = NSError(domain:"Error saving file", code:1001, userInfo:nil)
                    completion(path: destinationUrl.path!, error:error)
                }
            } else {
                let error = NSError(domain:"Error downloading file", code:1002, userInfo:nil)
                completion(path: destinationUrl.path!, error:error)
            }
        }
    
        class func loadFileAsync(url: NSURL, completion:(path:String, error:NSError!) -> Void) {
            let documentsUrl =  NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first as! NSURL
            let destinationUrl = documentsUrl.URLByAppendingPathComponent(url.lastPathComponent!)
            if NSFileManager().fileExistsAtPath(destinationUrl.path!) {
                println("file already exists [\(destinationUrl.path!)]")
                completion(path: destinationUrl.path!, error:nil)
            } else {
                let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
                let session = NSURLSession(configuration: sessionConfig, delegate: nil, delegateQueue: nil)
                let request = NSMutableURLRequest(URL: url)
                request.HTTPMethod = "GET"
                let task = session.dataTaskWithRequest(request, completionHandler: { (data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in
                    if (error == nil) {
                        if let response = response as? NSHTTPURLResponse {
                            println("response=\(response)")
                            if response.statusCode == 200 {
                                if data.writeToURL(destinationUrl, atomically: true) {
                                    println("file saved [\(destinationUrl.path!)]")
                                    completion(path: destinationUrl.path!, error:error)
                                } else {
                                    println("error saving file")
                                    let error = NSError(domain:"Error saving file", code:1001, userInfo:nil)
                                    completion(path: destinationUrl.path!, error:error)
                                }
                            }
                        }
                    }
                    else {
                        println("Failure: \(error.localizedDescription)");
                        completion(path: destinationUrl.path!, error:error)
                    }
                })
                task.resume()
            }
        }
    }
    

    以下是如何在您的代码中使用它:

    let url = NSURL(string: "http://www.mywebsite.com/myfile.pdf") 
    HttpDownloader.loadFileAsync(url, completion:{(path:String, error:NSError!) in
                    println("pdf downloaded to: \(path)")
                })
    

    【讨论】:

    【解决方案4】:

    如果您只需要将文本文件下载到String,您可以使用这种简单的方法,Swift 5

    let list = try? String(contentsOf: URL(string: "https://example.com/file.txt")!)
    

    如果您想要非可选的结果或错误处理:

    do {
        let list = try String(contentsOf: URL(string: "https://example.com/file.txt")!)
    }
    catch {
        // Handle error here
    }
    

    您应该知道网络操作可能需要一些时间,为了防止它在主线程中运行并锁定您的 UI,您可能希望异步执行代码,例如:

    DispatchQueue.global().async {
        let list = try? String(contentsOf: URL(string: "https://example.com/file.txt")!)
    }
    

    【讨论】:

    • 如何从url下载音频文件并保存在库中?
    【解决方案5】:

    只要您的应用程序处于前台,Devran 和 djunod 的解决方案就可以正常工作。如果在下载过程中切换到另一个应用程序,它会失败。我的文件大小约为 10 MB,下载需要一些时间。所以我需要我的下载功能在应用程序进入后台时也能正常工作。

    请注意,我在“功能”中打开了“后台模式/后台获取”。

    由于不支持完成处理程序,因此未封装解决方案。对此感到抱歉。

    --斯威夫特 2.3--

    import Foundation 
    class Downloader : NSObject, NSURLSessionDownloadDelegate
    {
        var url : NSURL? 
        // will be used to do whatever is needed once download is complete
        var yourOwnObject : NSObject?
    
        init(yourOwnObject : NSObject)
        {
            self.yourOwnObject = yourOwnObject
        }
    
        //is called once the download is complete
        func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didFinishDownloadingToURL location: NSURL)
        {
            //copy downloaded data to your documents directory with same names as source file
            let documentsUrl =  NSFileManager.defaultManager().URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask).first
            let destinationUrl = documentsUrl!.URLByAppendingPathComponent(url!.lastPathComponent!)
            let dataFromURL = NSData(contentsOfURL: location)
            dataFromURL?.writeToURL(destinationUrl, atomically: true)
    
            //now it is time to do what is needed to be done after the download
            yourOwnObject!.callWhatIsNeeded()
        }
    
        //this is to track progress
        func URLSession(session: NSURLSession, downloadTask: NSURLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)
        {
        }
    
        // if there is an error during download this will be called
        func URLSession(session: NSURLSession, task: NSURLSessionTask, didCompleteWithError error: NSError?)
        {
            if(error != nil)
            {
                //handle the error
                print("Download completed with error: \(error!.localizedDescription)");
            }
        }
    
        //method to be called to download
        func download(url: NSURL)
        {
            self.url = url
    
            //download identifier can be customized. I used the "ulr.absoluteString"
            let sessionConfig = NSURLSessionConfiguration.backgroundSessionConfigurationWithIdentifier(url.absoluteString)
            let session = NSURLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)
            let task = session.downloadTaskWithURL(url)
            task.resume()
        }
    }
    

    这里是如何调用--Swift 2.3--

        let url = NSURL(string: "http://company.com/file.txt")
        Downloader(yourOwnObject).download(url!)
    

    --斯威夫特 3--

    class Downloader : NSObject, URLSessionDownloadDelegate {
    
    var url : URL?
    // will be used to do whatever is needed once download is complete
    var yourOwnObject : NSObject?
    
    init(_ yourOwnObject : NSObject)
    {
        self.yourOwnObject = yourOwnObject
    }
    
    //is called once the download is complete
    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL)
    {
        //copy downloaded data to your documents directory with same names as source file
        let documentsUrl =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
        let destinationUrl = documentsUrl!.appendingPathComponent(url!.lastPathComponent)
        let dataFromURL = NSData(contentsOf: location)
        dataFromURL?.write(to: destinationUrl, atomically: true)
    
        //now it is time to do what is needed to be done after the download
        yourOwnObject!.callWhatIsNeeded()
    }
    
    //this is to track progress
    private func URLSession(session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)
    {
    }
    
    // if there is an error during download this will be called
    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
    {
        if(error != nil)
        {
            //handle the error
            print("Download completed with error: \(error!.localizedDescription)");
        }
    }
    
    //method to be called to download
    func download(url: URL)
    {
        self.url = url
    
        //download identifier can be customized. I used the "ulr.absoluteString"
        let sessionConfig = URLSessionConfiguration.background(withIdentifier: url.absoluteString)
        let session = Foundation.URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)
        let task = session.downloadTask(with: url)
        task.resume()
    }}
    

    这里是如何调用--Swift 3--

        let url = URL(string: "http://company.com/file.txt")
        Downloader(yourOwnObject).download(url!)
    

    【讨论】:

    • 您可以使用 swift 协议来使用委托并进一步封装您的解决方案。
    • 这个文件保存在哪里?
    • 它将文件下载到应用程序的文档文件夹中。您可以在 urlSession 方法中自定义它。
    【解决方案6】:

    这里是 Swift 4 版本:

    static func loadFileAsync(url: URL, completion: @escaping (String?, Error?) -> Void)
    {
        let documentsUrl =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first!
    
        let destinationUrl = documentsUrl.appendingPathComponent(url.lastPathComponent)
    
        if FileManager().fileExists(atPath: destinationUrl.path)
        {
            completion(destinationUrl.path, nil)
        }
        else
        {
            let session = URLSession(configuration: URLSessionConfiguration.default, delegate: nil, delegateQueue: nil)
            var request = URLRequest(url: url)
            request.httpMethod = "GET"
            let task = session.dataTask(with: request, completionHandler:
            {
                data, response, error in
                if error == nil
                {
                    if let response = response as? HTTPURLResponse
                    {
                        if response.statusCode == 200
                        {
                            if let data = data
                            {
                                if let _ = try? data.write(to: destinationUrl, options: Data.WritingOptions.atomic)
                                {
                                    completion(destinationUrl.path, error)
                                }
                                else
                                {
                                    completion(destinationUrl.path, error)
                                }
                            }
                            else
                            {
                                completion(destinationUrl.path, error)
                            }
                        }
                    }
                }
                else
                {
                    completion(destinationUrl.path, error)
                }
            })
            task.resume()
        }
    }
    

    【讨论】:

      【解决方案7】:

      斯威夫特 3

      你想一口一口地下载文件 并显示进行中视图 所以你想试试这段代码

      import UIKit
      
      class ViewController: UIViewController,URLSessionDownloadDelegate,UIDocumentInteractionControllerDelegate {
      
          @IBOutlet weak var img: UIImageView!
          @IBOutlet weak var btndown: UIButton!
          var urlLink: URL!
          var defaultSession: URLSession!
          var downloadTask: URLSessionDownloadTask!
          //var backgroundSession: URLSession!
          @IBOutlet weak var progress: UIProgressView!
          override func viewDidLoad() {
              super.viewDidLoad()
      
              // Do any additional setup after loading the view, typically from a nib.
      
              let backgroundSessionConfiguration = URLSessionConfiguration.background(withIdentifier: "backgroundSession")
              defaultSession = Foundation.URLSession(configuration: backgroundSessionConfiguration, delegate: self, delegateQueue: OperationQueue.main)
              progress.setProgress(0.0, animated: false)
          }
      
          func startDownloading () {
              let url = URL(string: "http://publications.gbdirect.co.uk/c_book/thecbook.pdf")!
              downloadTask = defaultSession.downloadTask(with: url)
              downloadTask.resume()
          }
      
          @IBAction func btndown(_ sender: UIButton) {
      
              startDownloading()
      
          }
      
          func showFileWithPath(path: String){
              let isFileFound:Bool? = FileManager.default.fileExists(atPath: path)
              if isFileFound == true{
                  let viewer = UIDocumentInteractionController(url: URL(fileURLWithPath: path))
                  viewer.delegate = self
                  viewer.presentPreview(animated: true)
              }
      
          }
      
      
          // MARK:- URLSessionDownloadDelegate
          func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
      
              print(downloadTask)
              print("File download succesfully")
      
              let path = NSSearchPathForDirectoriesInDomains(FileManager.SearchPathDirectory.documentDirectory, FileManager.SearchPathDomainMask.userDomainMask, true)
              let documentDirectoryPath:String = path[0]
              let fileManager = FileManager()
              let destinationURLForFile = URL(fileURLWithPath: documentDirectoryPath.appendingFormat("/file.pdf"))
      
              if fileManager.fileExists(atPath: destinationURLForFile.path){
                  showFileWithPath(path: destinationURLForFile.path)
                  print(destinationURLForFile.path)
              }
              else{
                  do {
                      try fileManager.moveItem(at: location, to: destinationURLForFile)
                      // show file
                      showFileWithPath(path: destinationURLForFile.path)
                  }catch{
                      print("An error occurred while moving file to destination url")
                  }
              }
      
      
      
          }
      
          func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
              progress.setProgress(Float(totalBytesWritten)/Float(totalBytesExpectedToWrite), animated: true)
          }
      
          func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
              downloadTask = nil
              progress.setProgress(0.0, animated: true)
              if (error != nil) {
                  print("didCompleteWithError \(error?.localizedDescription ?? "no value")")
              }
              else {
                  print("The task finished successfully")
              }
          }
      
          func documentInteractionControllerViewControllerForPreview(_ controller: UIDocumentInteractionController) -> UIViewController
          {
              return self
          }
      
          override func didReceiveMemoryWarning() {
              super.didReceiveMemoryWarning()
              // Dispose of any resources that can be recreated.
          }
      
      
      }
      

      使用此代码您想在应用程序的文档目录中自动下载文件存储

      此代码 100% 工作

      【讨论】:

      • 先生,就我而言,它的 totalBytesExpectedToWrite 总是返回 -1 。我正在下载一个 mp4 视频
      【解决方案8】:

      是的,您可以使用此代码非常轻松地从远程 URL 下载文件。 这段代码对我来说很好用。

      func DownlondFromUrl(){
         // Create destination URL 
      let documentsUrl:URL =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first as URL!
      let destinationFileUrl = documentsUrl.appendingPathComponent("downloadedFile.jpg")
      
      //Create URL to the source file you want to download
      let fileURL = URL(string: "https://s3.amazonaws.com/learn-swift/IMG_0001.JPG")
      
      let sessionConfig = URLSessionConfiguration.default
      let session = URLSession(configuration: sessionConfig)
      
      let request = URLRequest(url:fileURL!)
      
      let task = session.downloadTask(with: request) { (tempLocalUrl, response, error) in
          if let tempLocalUrl = tempLocalUrl, error == nil {
              // Success
              if let statusCode = (response as? HTTPURLResponse)?.statusCode {
                  print("Successfully downloaded. Status code: \(statusCode)")
              }
      
              do {
                  try FileManager.default.copyItem(at: tempLocalUrl, to: destinationFileUrl)
              } catch (let writeError) {
                  print("Error creating a file \(destinationFileUrl) : \(writeError)")
              }
      
          } else {
              print("Error took place while downloading a file. Error description: %@", error?.localizedDescription);
          }
      }
      task.resume()
      }
      

      【讨论】:

        【解决方案9】:

        在 Swift 5 中下载一个带有进度报告的文件,封装到一个复制粘贴友好的协议访问类中:

        protocol FileDownloadingDelegate: class {
            func updateDownloadProgressWith(progress: Float)
            func downloadFinished(localFilePath: URL)
            func downloadFailed(withError error: Error)
        }
        
        class FilesDownloader: NSObject, URLSessionDownloadDelegate {
            private weak var delegate: FileDownloadingDelegate?
        
            func download(from url: URL, delegate: FileDownloadingDelegate) {
                self.delegate = delegate
                let sessionConfig = URLSessionConfiguration.background(withIdentifier: url.absoluteString) // use this identifier to resume download after app restart
                let session = Foundation.URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)
                let task = session.downloadTask(with: url)
                task.resume()
            }
        
            func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
                DispatchQueue.main.async { self.delegate?.downloadFinished(localFilePath: location) }
            }
        
            func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
                DispatchQueue.main.async { self.delegate?.updateDownloadProgressWith(progress: Float(totalBytesWritten)/Float(totalBytesExpectedToWrite)) }
            }
        
            func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
                guard let theError = error else { assertionFailure("something weird happened here"); return }
                DispatchQueue.main.async { self.delegate?.downloadFailed(withError: theError) }
            }
        
        }
        

        使用方法:

        class MyViewController: UIViewController {
        
            private lazy var downloader = FilesDownloader()
        
            func downloadFile(from url: URL) {
                downloader.download(from: url, delegate: self)
            }
        
        }
        
        extension MyViewController: FileDownloadingDelegate {
            func updateDownloadProgressWith(progress: Float) {
                // self.downloadProgressView.setProgress(progress, animated: true)
            }
        
            func downloadFinished(tempFilePath: URL) {
                print("downloaded to \(tempFilePath)")
                // resave the file into your desired place using 
                // let dataFromURL = NSData(contentsOf: location)
                // dataFromURL?.write(to: yourDesiredFileUrl, atomically: true)
            }
        
            func downloadFailed(withError error: Error) {
                // handle the error
            }
        }
        

        【讨论】:

          【解决方案10】:

          在尝试了上述一些建议但没有成功(Swift 版本...)后,我最终使用了官方文档:https://developer.apple.com/documentation/foundation/url_loading_system/downloading_files_from_websites

          let downloadTask = URLSession.shared.downloadTask(with: url) {
              urlOrNil, responseOrNil, errorOrNil in
              // check for and handle errors:
              // * errorOrNil should be nil
              // * responseOrNil should be an HTTPURLResponse with statusCode in 200..<299
              
              guard let fileURL = urlOrNil else { return }
              do {
                  let documentsURL = try
                      FileManager.default.url(for: .documentDirectory,
                                              in: .userDomainMask,
                                              appropriateFor: nil,
                                              create: false)
                  let savedURL = documentsURL.appendingPathComponent(fileURL.lastPathComponent)
                  try FileManager.default.moveItem(at: fileURL, to: savedURL)
              } catch {
                  print ("file error: \(error)")
              }
          }
          downloadTask.resume()
          

          【讨论】:

            【解决方案11】:

            仅试用此代码 Swift 3.0 首先创建 NS 对象文件 将此代码复制到创建的文件中

            import UIKit
            
            class Downloader : NSObject, URLSessionDownloadDelegate {
            
                var url : URL?
                // will be used to do whatever is needed once download is complete
                var obj1 : NSObject?
            
                init(_ obj1 : NSObject)
                {
                    self.obj1 = obj1
                }
            
                //is called once the download is complete
                func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL)
                {
                    //copy downloaded data to your documents directory with same names as source file
                    let documentsUrl =  FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first
                    let destinationUrl = documentsUrl!.appendingPathComponent(url!.lastPathComponent)
                    let dataFromURL = NSData(contentsOf: location)
                    dataFromURL?.write(to: destinationUrl, atomically: true)
            
                    //now it is time to do what is needed to be done after the download
                    //obj1!.callWhatIsNeeded()
                }
            
                //this is to track progress
                private func URLSession(session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64)
                {
                }
            
                // if there is an error during download this will be called
                func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?)
                {
                    if(error != nil)
                    {
                        //handle the error
                        print("Download completed with error: \(error!.localizedDescription)");
                    }
                }
            
                //method to be called to download
                func download(url: URL)
                {
                    self.url = url
            
                    //download identifier can be customized. I used the "ulr.absoluteString"
                    let sessionConfig = URLSessionConfiguration.background(withIdentifier: url.absoluteString)
                    let session = Foundation.URLSession(configuration: sessionConfig, delegate: self, delegateQueue: nil)
                    let task = session.downloadTask(with: url)
                    task.resume()
                }}
            

            然后复制下面的代码并把代码放在你要下载文件的地方

             object = "http://www.mywebsite.com/myfile.pdf"
                   let url1 = URL(string: object!)
                    Downloader(url1! as NSObject).download(url: url1!)
            

            【讨论】:

            • 这段代码在 Swift 3.0 中完全可以运行
            【解决方案12】:

            iOS 13 Swift 5、5.1

            @IBAction func btnDownload(_ sender: Any) {
                
                // file location to save download file
                let destination: DownloadRequest.DownloadFileDestination = { _, _ in
                    var documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
                    documentsURL.appendPathComponent(statementPDF)
                    return (documentsURL, [.removePreviousFile])
                }
                
                // Alamofire to download file
                Alamofire.download("http://pdf_url", to: destination).responseData { response in
                    hideLoader()
                    switch response.result {
                    case .success:
                        // write something here
                        if response.destinationURL != nil {
                            showAlertMessage(titleStr: APPNAME, messageStr: "File Saved in Documents!")
                            
                        }
                    case .failure:
                        showAlertMessage(titleStr: APPNAME, messageStr: response.result.error.debugDescription)
                    }
                }
            }
            

            请将这些权限添加到 info.plist 中,以便您可以在Document Directory 中查看下载文件

            <key>UIFileSharingEnabled</key>
            <true/>
            <key>LSSupportsOpeningDocumentsInPlace</key>
            <true/>
            

            【讨论】:

              【解决方案13】:

              斯威夫特 3

              class ViewController: UIViewController {
                  var urlLink: URL!
                  var defaultSession: URLSession!
                  var downloadTask: URLSessionDownloadTask!
              }
              
              // MARK: Button Pressed
                  @IBAction func btnDownloadPressed(_ sender: UIButton) {
                      let urlLink1 = URL.init(string: "https://github.com/VivekVithlani/QRCodeReader/archive/master.zip")
                      startDownloading(url: urlLink!)
              }
                  @IBAction func btnResumePressed(_ sender: UIButton) {
                  downloadTask.resume()
              }
              
              @IBAction func btnStopPressed(_ sender: UIButton) {
                  downloadTask.cancel()
              }
              
              @IBAction func btnPausePressed(_ sender: UIButton) {
                  downloadTask.suspend()
              }
              
                  func startDownloading (url:URL) {
                      let backgroundSessionConfiguration = URLSessionConfiguration.background(withIdentifier: "backgroundSession")
                      defaultSession = Foundation.URLSession(configuration: backgroundSessionConfiguration, delegate: self, delegateQueue: OperationQueue.main)
                      downloadProgress.setProgress(0.0, animated: false)
                      downloadTask = defaultSession.downloadTask(with: urlLink)
                      downloadTask.resume()
                  }
              
              // MARK:- URLSessionDownloadDelegate
              func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL) {
                  print("File download succesfully")
              }
              
              func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didWriteData bytesWritten: Int64, totalBytesWritten: Int64, totalBytesExpectedToWrite: Int64) {
                  downloadProgress.setProgress(Float(totalBytesWritten)/Float(totalBytesExpectedToWrite), animated: true)
              }
              
              func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
                  downloadTask = nil
                  downloadProgress.setProgress(0.0, animated: true)
                  if (error != nil) {
                      print("didCompleteWithError \(error?.localizedDescription)")
                  }
                  else {
                      print("The task finished successfully")
                  }
              }
              

              【讨论】:

              • 我在downloadProgress 中遇到错误:Use of unresolved identifier。如何修复它? downloadProgress变量的类型是什么
              • downloadProgress 是 UIProgressView 类
              【解决方案14】:

              您还可以使用让生活更轻松的第三方库,例如 Just

              Just.get("http://www.mywebsite.com/myfile.pdf")
              

              更多精彩的 Swift 内容在这里 https://github.com/matteocrippa/awesome-swift

              【讨论】:

                【解决方案15】:

                后台会话(URLSessionDownloadTaskURLSessionUploadTask)是background transfer 方法的一部分,即使应用程序被终止,您也可以在后台模式下下载/上传/缓存文件。在这种情况下,当任务完成时,iOS 会唤醒它(在后台)并允许在有限的时间范围内进行一些竞争阻止。之所以有效,是因为下载任务是在nsurlsessionddaemon process[About]上执行的

                [Background tasks]

                【讨论】:

                  【解决方案16】:

                  使用URLSessionDownloadTask在后台下载文件,即使应用程序终止也可以完成。

                  欲了解更多信息,请参阅:

                  https://www.ralfebert.de/snippets/ios/urlsession-background-downloads/

                  它还展示了如何为并行运行的多个任务实现进度监控:

                  【讨论】:

                  • 但主要任务是如何从设备中隐藏,数据只能通过应用程序访问。
                  【解决方案17】:

                  一个简单、健壮和优雅的下载管理器,支持同时下载,使用闭包语法来跟踪进度和完成情况。用 Swift 编写,使用 Here

                  并像它一样使用

                  func downloadGIF(url: String) {
                      let filename = url
                      let range: Range<String.Index> = filename.range(of:"media/")!
                      let lastrange: Range<String.Index> = filename.range(of:"/200w_d")!
                      let finalPath = String(filename[range.lowerBound..<lastrange.lowerBound])
                      filename[range.lowerBound..<lastrange.lowerBound]
                      let replaceFirstWords = finalPath.replace(string: "media/", replacement: "SocialStatus_GIF_")
                      let destinationUrl = "\(replaceFirstWords).gif"
                  
                      let request = URLRequest(url: URL(string: imageData.bg_image)!)
                      viewProgress.isHidden = false
                      self.btnDownload.isHidden = true
                      setSharingButtonFalse()
                      let downloadKey = self.downloadManager.downloadFile(withRequest: request,
                                                                          withName: destinationUrl,
                                                                          shouldDownloadInBackground: true,
                                                                          onProgress:  { [weak self] (progress) in
                                                                              self?.viewProgress.progress = CGFloat(progress)
                                                                              let val = progress * 100
                                                                              print("val 1 == \(val)")
                                                                              DispatchQueue.main.async {
                                                                                  self?.viewProgress.setProgressText("\(Int(val))")
                                                                              }
                  
                      }) { [weak self] (error, url) in
                          if let error = error {
                              print("Error = \(error as NSError)")
                              self!.isDownloaded = false
                              self!.viewProgress.isHidden = true
                              self!.setSharingButtonTrue()
                              self?.viewProgress.setProgressText("\(0)")
                              print("handle error since couldn't save GIF")
                          } else {
                              if let url = url {
                                  self!.isDownloaded = true
                                  self!.saveGIFDownloaded()
                                  self!.viewProgress.isHidden = true
                                  self!.setSharingButtonTrue()
                                  self!.createAlbum()
                                  self!.saveGIF(url: url.absoluteURL)
                  
                              }
                          }
                      }
                  
                  }
                  

                  【讨论】:

                    猜你喜欢
                    • 1970-01-01
                    • 1970-01-01
                    • 2012-12-10
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 1970-01-01
                    • 2022-11-03
                    相关资源
                    最近更新 更多