¿Cómo descargar un archivo rápidamente?

Acabo de empezar a aprender la progtwigción Apple rápida para iOS procedente de Android. Básicamente, ahora puedo leer y manipular código rápido y también aprendí algunas clases comunes usadas en la progtwigción rápida de iOS, pero todavía tengo cierta confusión con la syntax y todo.

Estoy tratando de descargar el archivo. Como, digamos que viene de esta URL

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

en un clic del botón. Tal vez con progreso visual también

Al buscar aquí en stackoverflow, me encontré con Alamofire. Podría intentarlo, pero no estoy seguro de si esta es la mejor manera para hacerlo.

Entonces, me gustaría preguntar cómo y cuáles son mis opciones (iOS7 e iOS8) para lograr mi objective. Además, ¡los pros y los contras serían increíbles!

Ejemplo de clase de descarga sin 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() } } 

Esta es la forma de usarlo en tu propio código:

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

Versión de Swift 3

También tenga en cuenta que para descargar archivos grandes en el disco en su lugar, en la memoria. ver `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() } } 

Aquí hay un ejemplo que muestra cómo sincronizar y sincronizar.

 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() } } } 

A continuación, le mostramos cómo usarlo en su código:

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

Si necesita descargar solo el archivo de texto en String , puede usar esta sencilla manera, Swift 3 :

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

En caso de que desee un resultado no opcional o manejo de errores:

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

Debe saber que las operaciones de red pueden tardar un tiempo, para evitar que se ejecute en el hilo principal y bloquear su UI, es posible que desee ejecutar el código de forma asincrónica, por ejemplo:

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

Las soluciones de Devran y de djunod funcionan siempre que su aplicación esté en primer plano. Si cambia a otra aplicación durante la descarga, falla. El tamaño de mis archivos es de alrededor de 10 MB y me lleva tiempo descargarlo. Así que necesito que mi función de descarga funcione incluso cuando la aplicación esté en segundo plano.

Tenga en cuenta que he activado “Modos de fondo / búsqueda de fondo” en “Capacidades”.

Como el manejador de finalización no era compatible, la solución no está encapsulada. Lo siento por eso.

–Swift 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() } } 

Y aquí está cómo llamar –Swift 2.3–

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

–Swift 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() }} 

Y aquí está cómo llamar –Swift 3–

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

Swift 3

Desea descargar el archivo por mordida y mostrar en vista de progreso para que desee probar este código

 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. } } 

uso de este código para descargar automáticamente la tienda de archivos en Document Directory en su aplicación

este código 100% de trabajo

Aquí está la versión de 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() } } 

Pruebe este código solo Swift 3.0 Primero cree el archivo de objeto NS Copie este código en el archivo creado

 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() }} 

luego copie el código a continuación y coloque el código en lugar de que desee descargar el archivo

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

Swift 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") } } 

Sí, puede descargar archivos de la Url remota con facilidad usando este código. Este código funciona bien para mí.

 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() } 

Use URLSessionDownloadTask para descargar archivos en segundo plano para que puedan completarse incluso si la aplicación finaliza.

Para más información, ver:

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

También muestra cómo implementar la supervisión de progreso para múltiples tareas que se ejecutan en paralelo: