Comment télécharger un fichier dans swift?

je viens de commencer à apprendre la programmation apple swift pour iOS venant d'android. Fondamentalement, je peux maintenant lire et manipuler le code swift et j'ai aussi appris quelques classes communes utilisées dans la programmation iOS swift, mais j'ai encore une certaine confusion avec la syntaxe et tout.

j'essaie de télécharger le fichier. Comme, disons venant de cette URL

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

en un clic de bouton. Peut-être avec le progrès visuel aussi

en cherchant ici dans stackoverflow, Je tombé sur Alamofire. Je peux essayer, mais je ne suis pas sûr que ce soit la meilleure façon de le faire.

donc, je voudrais demander comment et quelles sont mes options (iOS7 et iOS8) pour atteindre mon objectif. Aussi, les avantages et les inconvénients serait génial!

33
demandé sur Petter Friberg 2015-01-29 19:35:09

10 réponses

exemple de classe downloader sans 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()
    }
}

C'est comment l'utiliser dans votre propre code:

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

Swift 3 Version

notez aussi de télécharger de gros fichiers sur le disque à la place en mémoire. voir ' 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()
    }
}
38
répondu Devran Cosmo Uenal 2016-09-16 09:20:46

Voici un exemple qui montre comment faire de synchronisation et asynchrone.

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

Voici comment l'utiliser dans votre code:

let url = NSURL(string: "http://www.mywebsite.com/myfile.pdf") 
HttpDownloader.loadFileAsync(url, completion:{(path:String, error:NSError!) in
                println("pdf downloaded to: \(path)")
            })
17
répondu djunod 2015-05-07 16:33:05

les solutions de Devran et djunod fonctionnent aussi longtemps que votre application est au premier plan. Si vous passez à une autre application pendant le téléchargement, il échoue. Mes tailles de fichier sont d'environ 10 MB et il faut un certain temps pour télécharger. Donc j'ai besoin de ma fonction de téléchargement fonctionne même lorsque l'application passe en arrière-plan.

s'il vous Plaît noter que je suis passé SUR les "Modes de Fond / Fond d'Extraction" à "Capacités".

depuis completionhandler n'a pas été supporté la solution est non encapsulées. Désolé à ce sujet.

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

Et voici comment l'appelez-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()
}}

Et voici comment l'appelez-Swift 3--

    let url = URL(string: "http://company.com/file.txt")
    Downloader(yourOwnObject).download(url!)
14
répondu Ahmet Akkök 2017-03-29 13:34:20

si vous avez besoin de télécharger uniquement un fichier texte dans String vous pouvez utiliser cette manière simple, Swift 3:

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

Dans le cas où vous voulez non résultat facultatif ou d'erreur de manipulation:

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

vous devez savoir que les opérations réseau peuvent prendre un certain temps, pour l'empêcher de s'exécuter dans le thread principal et de verrouiller votre UI, vous pouvez vouloir exécuter le code de manière asynchrone, par exemple:

DispatchQueue.global().async {
    let list = try? String(contentsOf: URL(string: "https://example.com/file.txt")!)
}
13
répondu Dmitriy 2016-08-03 09:49:17

Swift 3

vous voulez télécharger Fichier morsure par Morsure et montrer en cours de vue si vous voulez essayer ce code

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


}

utilisation de ce code vous souhaitez télécharger le fichier stocker automatiquement dans le répertoire de Document de votre application

ce code fonctionne à 100%

4
répondu Rob-4608 2017-05-18 08:38:25

Voici la version 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()
    }
}
2
répondu Sascha Simon 2018-03-11 09:08:17

essayez ce Code seulement Swift 3.0 D'abord créer un fichier D'objet NS Copier ce code dans le fichier créé

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

puis copiez le Code ci-dessous et mettez le code à la place de vous voulez télécharger le fichier

 object = "http://www.mywebsite.com/myfile.pdf"
       let url1 = URL(string: object!)
        Downloader(url1! as NSObject).download(url: url1!)
1
répondu Rob-4608 2017-05-18 08:30:00

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")
    }
}
0
répondu Vivek 2017-01-11 07:00:25

Oui, vous pouvez très facilement télécharger des fichiers à partir de L'Url distante en utilisant ce code. Ce Code fonctionne très bien pour moi.

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()
}
0
répondu Ayush Dixit 2018-07-20 12:06:20

Utiliser URLSessionDownloadTask télécharger des fichiers en arrière-plan pour qu'ils puissent être complétés même si l'application est terminée.

pour plus d'information voir:

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

Il montre également comment mettre en œuvre le suivi des progrès pour les tâches multiples exécutées en parallèle:

-1
répondu Azar 2017-05-18 08:16:26