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!
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()
}
}
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)")
})
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!)
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")!)
}
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%
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()
}
}
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!)
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")
}
}
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()
}
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: