2017-03-19 9 views
2

Es gibt eine tableViewController mit 5 Zellen. Wenn ich auf eine Zelle klicke, wird der Download gestartet, wenn die Datei nicht gefunden wird.swift: nsurlsession Dateien herunterladen

override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 
if indexPath.row > 0 { 

     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%d.pdf",indexPath.row)) 

     if fileManager.fileExists(atPath: destinationURLForFile.path){ self) 
     }else{ 

      var downloadTask: URLSessionDownloadTask! 

      index = indexPath.row 

      let url = URL(string: "http://publications.gbdirect.co.uk/c_book/thecbook.pdf")! 
      downloadTask = backgroundSession.downloadTask(with: url) 
      downloadTask.resume() 

     }} 

    func urlSession(_ session: URLSession, 
       downloadTask: URLSessionDownloadTask, 
       didFinishDownloadingTo location: URL){ 

    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%d.pdf",index)) 

    do { 
     try fileManager.moveItem(at: location, to: destinationURLForFile) 
     }catch{ 
      print("An error occurred while moving file to destination url") 
     } 
} 

Das Problem ist, dass eine die das Herunterladen von Dateien stoppt, wenn ich 2 Dateien auf einmal herunterladen. Wie man es repariert?

Antwort

1

Ein paar Gedanken:

  1. Eine einzige numerische index Eigenschaft ist offensichtlich unzureichend Überblick über die mehrere Downloads zu halten, die im Gange sein könnte. Sie benötigen eine Struktur, um die Korrelation zwischen Downloads und ihren eventuellen Dateinamen im Ordner "Dokumente" zu verfolgen. Es könnte sein:

    struct Download { 
        enum Status { 
         case notStarted 
         case started 
         case finished 
         case failed(Error?) 
        } 
    
        /// URL of resource on web server 
    
        let remoteURL: URL 
    
        /// URL of file in Documents folder 
    
        let localURL: URL 
    
        /// The status of the download 
    
        var status: Status 
    } 
    

    Nun, da Sie einen Typ haben den Überblick über den Zustand eines einzelnen Download zu halten, eine Reihe dieser Download Objekte erstellen:

    var downloads = [Download]() 
    
  2. Sie könnten, dass bevölkern in viewDidLoad oder so ähnlich:

    override func viewDidLoad() { 
        super.viewDidLoad() 
    
        // create the `Download` objects, e.g. I'll create one here 
    
        let remoteURL = URL(string: "http://publications.gbdirect.co.uk/c_book/thecbook.pdf")! 
        let fileURL = try! FileManager.default.url(for: .documentDirectory, in: .userDomainMask, appropriateFor: nil, create: false) 
         .appendingPathComponent("file0.pdf") 
    
        let status: Download.Status 
        if try! fileURL.checkResourceIsReachable() { 
         status = .finished 
        } else { 
         status = .notStarted 
        } 
    
        downloads.append(Download(remoteURL: remoteURL, localURL: fileURL, status: status)) 
    
        // since you're dealing with background session (e.g. tasks may have been previously 
        // scheduled), let's iterate through any pending tasks, updating status accordingly 
    
        backgroundSession.getAllTasks { tasks in 
         for task in tasks { 
          guard let index = self.downloads.index(where: { $0.remoteURL == task.originalRequest?.url }) else { 
           print("cannot find download for \(task.originalRequest?.url)") 
           return 
          } 
          self.downloads[index].status = .started 
         } 
        } 
    } 
    
  3. Wenn der Download abgeschlossen ist, können Sie jetzt sehen, genau das Download in ou r Reihe von Downloads, um die Datei-URL zu bestimmen:

    func urlSession(_ session: URLSession, downloadTask: URLSessionDownloadTask, didFinishDownloadingTo location: URL){ 
        guard let index = downloads.index(where: { $0.remoteURL == downloadTask.originalRequest?.url }) else { 
         print("cannot find download for \(downloadTask.originalRequest?.url)") 
         return 
        } 
    
        do { 
         try FileManager.default.moveItem(at: location, to: downloads[index].localURL) 
         downloads[index].status = .finished 
        } catch { 
         print("An error occurred while moving file to destination url: \(error.localizedDescription)") 
         downloads[index].status = .failed(error) 
        } 
    } 
    
  4. Es ist erwähnenswert, dass die Logik, die sagt „wenn die Datei nicht existiert, dann Download starten“ ist höchstwahrscheinlich unzureichend. Sicher, wenn die Datei existiert, ist der Download abgeschlossen. Was aber, wenn ein Download bereits gestartet wurde, aber noch nicht abgeschlossen ist? Sie möchten wahrscheinlich keinen neuen Download starten, wenn ein zuvor initiierter Download noch nicht abgeschlossen ist.

    override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { 
        if indexPath.row > 0 { 
         let index = indexPath.row - 1 // for some reason you're looking at indexes greater than zero, so let's adjust our index for a zero-based index within our array 
         switch downloads[index].status { 
         case .notStarted: 
          let downloadTask = backgroundSession.downloadTask(with: downloads[index].remoteURL) 
          downloads[index].status = .started 
          downloadTask.resume() 
         default: 
          break 
         } 
        } 
    } 
    

Nun, ich will nicht zu verloren oben in die Details dieser Code-Schnipsel zu bekommen, sondern ich möchte sicherstellen, dass Sie das grundlegende Konzept grok, nämlich, dass Sie nicht haben können ein einzelner numerischer Index, aber Sie brauchen eine Sammlung (ein Array oder ein Wörterbuch), um alle verschiedenen Downloads im Auge zu behalten, die zu einem bestimmten Zeitpunkt ausgeführt werden können.

0

Sie können nicht zwei Dateien gleichzeitig herunterladen, wenn Sie einzelne Variablen verwenden (index und downloadTask). Wann immer der Benutzer die zweite Zelle auswählt, wird ein neuer Wert für den Index gesetzt, so dass dieser Wert in urlSession verwendet wird: downloadTask: didFinishDownloadingTo: ist ein Fehler, wenn er von der ersten Aufgabe aufgerufen wird.

Sie müssen die Werte in einer Sammlung zu halten, zum Beispiel eine Reihe von Tupeln, um den Index zu halten, um die Aufgabe und andere Informationen über die Datei, zum Beispiel des Dateipfad.

+0

Ist es möglich, eine Zelle Index 'downloadTask' zuweisen? –

+0

Ich habe dir das nicht gesagt. Ich sagte, du kannst zum Beispiel ein Tupla benutzen, um beide Werte zu behalten. – Gabriel

+0

Wie geht das im Code? –