2

Mit XCode-8.2.1, Swift-3.0.2 und iOS-10.2.1,Wie wird die serielle Warteschlange für URLSession-Aufgaben synchronisiert?

Ich versuche, zwei verschiedene URLSession.shared.dataTasks (die erste ist eine einfache URL-Anfrage und die zweite ist eine POST-Anfrage).

Da meine erste dataTask ein Ergebnis liefert, das in der httpBody der zweiten dataTask benötigt wird, sollen die beiden URLSession.shared.dataTasks nacheinander hintereinander laufen! (und auch der präparative Code soll fortlaufend ablaufen).

Ich habe versucht, so weit, mit zwei aufeinanderfolgenden serialQueue.sync{} Warteschlangen. Aber ich musste erkennen, dass der Code nicht in der Reihenfolge funktioniert, die ich möchte.

Der Druck-Anweisung im Protokoll entpuppen sich wie folgt zusammen:

Hmmmmmm 2 
Hmmmmmm 1 
Hmmmmmm 3 

(anstelle von 1, 2, 3 je nach Bedarf)!

Wie erhalten Sie die Bestellung 1, 2, 3 ??

(dh wie kann man die httpBody des zweiten dataTask stellen Sie sicher, von der ersten dataTask mit einem Ergebnis kommen gefüllt werden?)

Hier ist mein Code: (nicht ausführbare Datei als URL wurden herausgenommen - aber Sie bekommen den Punkt)!

import UIKit 

class ViewController: UIViewController { 

    let serialQueue = DispatchQueue(label: "myResourceQueue") 
    var stationID: Int = 0 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Do any additional setup after loading the view, typically from a nib. 


     self.serialQueue.sync { 
      let myResourceURL = URL(string: "myQueryString1") 
      let task = URLSession.shared.dataTask(with: myResourceURL!) { (data, response, error) in 
       if (error != nil) { 
        // print(error.debugDescription) 
       } else { 
        if let myData = data { 
         do { 
          let myJson = try JSONSerialization.jsonObject(with: myData, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject 
          // print(myJson) 
          // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
          print("Hmmmmmm 1") 
          // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
         } catch { 
          // error 
         } 
        } 
       } 
      } 
      task.resume() 
     } 
     self.serialQueue.sync { 
      var request = URLRequest(url: URL(string: "myQueryString2")!) 
      request.httpMethod = "POST" 
      request.addValue("API_id", forHTTPHeaderField: "Authorization") 
      request.addValue("application/xml", forHTTPHeaderField: "Content-Type") 
      // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
      print("Hmmmmmm 2") 
      // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
      let postString: String = "My_XML_POST_Body" 
      request.httpBody = postString.data(using: .utf8) 
      let task = URLSession.shared.dataTask(with: request) { data, response, error in 
       // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
       print("Hmmmmmm 3") 
       // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
      } 
      task.resume() 
     } 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 
} 

Irgendwelche Hilfe geschätzt!

+0

lustig - Ich möchte das gleiche wissen, 19 Stunden später! :) – Fattie

+0

Sie haben Recht, URLSession.shared.dataTask scheint aus serialQueue springen. – Fattie

+0

Eine andere Möglichkeit, dies zu tun, ist mit einer Operationswarteschlange, die entweder (a) "maxConcurrentOperationCount" von "1" hat; oder (b) für die Sie Abhängigkeiten zwischen den Operationen herstellen. Damit dies funktioniert, müssen Sie eine asynchrone Unterklasse "Operation"/"NSOperation" erstellen, die Sie unter http://stackoverflow.com/questions/32322386/how-to-download-multiple-files-sequentially-using-nsurlsession- Downloadtask-in-s/32322851 # 32322851. – Rob

Antwort

2

ich endlich eine Lösung gefunden:

Inspiriert von this answer, ich URLSessionDataDelegate eingeführt, zusammen mit seinem Delegierten Rückruf-Methoden (dh didReceive response:, didReceive data: und didCompleteWithError error:

. Wichtig: Sie benötigen einrichten URLSession mit einem Delegaten, damit die Callback-Methoden von URLSessionDelegate funktionieren: Verwenden Sie URLSession (configuration: ....) wie hier gezeigt:

let URLSessionConfig = URLSessionConfiguration.default 
let session = URLSession(configuration: URLSessionConfig, delegate: self, delegateQueue: OperationQueue.main) 

Danach, Sie sind gut zu gehen, das heißt das Protokoll ist nun wie erwartet:

Hmmmmmm 1 
Hmmmmmm 2 
Hmmmmmm 3 

Hier ist der endgültige Code ist (wieder nicht ausführbare Datei als URL wurden herausgenommen - aber Sie erhalten den Punkt)!

import UIKit 

class ViewController: UIViewController, URLSessionDataDelegate { 

    var stationID: Int = 0 
    let URLSessionConfig = URLSessionConfiguration.default 
    var session: URLSession? 
    var task1: URLSessionTask? 
    var task2: URLSessionTask? 

    override func viewDidLoad() { 
     super.viewDidLoad() 
     // Do any additional setup after loading the view, typically from a nib. 

     self.session = URLSession(configuration: URLSessionConfig, delegate: self, delegateQueue: OperationQueue.main) 

     // prepare dataTask Nr 1 
     let myResourceURL = URL(string: "myQueryString1") 
     self.task1 = session?.dataTask(with: myResourceURL!) 

     // start dataTask Nr 1 (URL-request) 
     self.task1?.resume() 
    } 

    // Optional: Use this method if you want to get a response-size information 
    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive response: URLResponse, completionHandler: @escaping (URLSession.ResponseDisposition) -> Void) { 

     // print(Int(response.expectedContentLength)) 
     completionHandler(URLSession.ResponseDisposition.allow) 
    } 

    func urlSession(_ session: URLSession, dataTask: URLSessionDataTask, didReceive data: Data) { 

     if dataTask == self.task1 { 
      do { 
       let myJson = try JSONSerialization.jsonObject(with: myData, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject 
       // print(myJson) 
       // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
       print("Hmmmmmm 1") 
       // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 

       // prepare dataTask Nr 2 
       self.task2 = self.session?.dataTask(with: self.prepareMyURLRequest()) 
      } catch { 
       // error 
      } 
     } else if dataTask == self.task2 { 

      // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
      print("Hmmmmmm 3") 
      // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 

     } else { 
      print("unknown dataTask callback") 
     } 
    } 

    func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) { 
     if (error != nil) { 
      // print(error.debugDescription) 
     } else if task == self.task1 { 

      // start dataTask Nr 2 (POST URL-request) 
      self.task2?.resume() 
     } 
    } 

    func prepareMyURLRequest() -> URLRequest { 
     var request = URLRequest(url: URL(string: "myQueryString2")!) 
     request.httpMethod = "POST" 
     request.addValue("API_id", forHTTPHeaderField: "Authorization") 
     request.addValue("application/xml", forHTTPHeaderField: "Content-Type") 
     // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
     print("Hmmmmmm 2") 
     // !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! 
     let postString: String = "My_XML_POST_Body" 
     request.httpBody = postString.data(using: .utf8) 
     return request 
    } 

    override func didReceiveMemoryWarning() { 
     super.didReceiveMemoryWarning() 
     // Dispose of any resources that can be recreated. 
    } 

} 
+0

iKK - aber Sie rufen sie nur sequentiell an. Recht? du verwendest keine serialQueue, ich glaube nicht ?? – Fattie

+0

iKK - Das ist in Ordnung. Aber offensichtlich müssen Sie diese Arbeit mit einer Delegierten-basierten Implementierung nicht durchgehen.Sie können die gleiche Sache mit weit einfacheren Abschluss-Handler-Muster erreichen. – Rob

+0

Danke Rob. Hast du ein solches Beispiel zur Hand, um es hier zu zeigen? – iKK

Verwandte Themen