2014-11-06 5 views
44

Kann ich irgendwie eine synchrone HTTP-Anfrage über NSURLSession in Swift machen?Kann ich irgendwie eine synchrone HTTP-Anfrage über NSURLSession in Swift machen

kann ich eine asynchrone Anforderung über den folgenden Code tun:

if let url = NSURL(string: "https://2ch.hk/b/threads.json") { 
      let task = NSURLSession.sharedSession().dataTaskWithURL(url) { 
       (data, response, error) in 

       var jsonError: NSError? 
       let jsonDict = NSJSONSerialization.JSONObjectWithData(data, options: nil, error: &jsonError) as [String: AnyObject] 
       if jsonError != nil { 
        return 
       } 

       // ... 
      } 
      task.resume() 
     } 

Aber was synchrone Anforderung?

Vielen Dank im Voraus.

+0

Check this out http://stackoverflow.com/questions/21198404/nsurlsession-with-nsblockoperation-and-queues – Ian

Antwort

-2

Seien Sie vorsichtig mit synchronen Anfragen, da dies zu einer schlechten Benutzererfahrung führen kann, aber ich weiß manchmal, dass es notwendig ist. Für synchrone Anfragen verwenden NSURLConnection: "The Eskimo"

func synchronousRequest() -> NSDictionary { 

     //creating the request 
     let url: NSURL! = NSURL(string: "exampledomain/...") 
     var request = NSMutableURLRequest(URL: url) 
     request.HTTPMethod = "GET" 
     request.addValue("application/json", forHTTPHeaderField: "Content-Type") 


     var error: NSError? 

     var response: NSURLResponse? 

     let urlData = NSURLConnection.sendSynchronousRequest(request, returningResponse: &response, error: &error) 

     error = nil 
     let resultDictionary: NSDictionary = NSJSONSerialization.JSONObjectWithData(urlData!, options: NSJSONReadingOptions.MutableContainers, error: &error) as! NSDictionary 

     return resultDictionary 
    } 
+2

dies funktioniert nicht auf Swift 2 mehr. Apple hat offenbar entschieden, dass wir keine synchronen Anfragen benötigen. – SpaceDog

+0

@SpaceDog Vielen Dank für Ihren Kommentar. Könnten Sie bitte erklären, warum Apple das tut und uns den "richtigen Weg" nennt oder ein hilfreiches Tutorial oder eine Dokumentation zur Verfügung stellt? Danke –

26

Apple thread discussing the same issue.

+ (NSData *)sendSynchronousRequest:(NSURLRequest *)request 
    returningResponse:(__autoreleasing NSURLResponse **)responsePtr 
    error:(__autoreleasing NSError **)errorPtr { 
    dispatch_semaphore_t sem; 
    __block NSData *  result; 

    result = nil; 

    sem = dispatch_semaphore_create(0); 

    [[[NSURLSession sharedSession] dataTaskWithRequest:request 
     completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) { 
     if (errorPtr != NULL) { 
      *errorPtr = error; 
     } 
     if (responsePtr != NULL) { 
      *responsePtr = response; 
     } 
     if (error == nil) { 
      result = data; 
     } 
     dispatch_semaphore_signal(sem); 
    }] resume]; 

    dispatch_semaphore_wait(sem, DISPATCH_TIME_FOREVER); 

    return result; 
} 

Antwort von Quinn Apple Developer Relations, Entwickler Technical Support, Core Betriebssystem/Hardware

50

können Sie verwenden diese NSURLSession Erweiterung eine synchrone Methode hinzufügen:

extension NSURLSession { 
    func synchronousDataTaskWithURL(url: NSURL) -> (NSData?, NSURLResponse?, NSError?) { 
     var data: NSData?, response: NSURLResponse?, error: NSError? 

     let semaphore = dispatch_semaphore_create(0) 

     dataTaskWithURL(url) { 
      data = $0; response = $1; error = $2 
      dispatch_semaphore_signal(semaphore) 
     }.resume() 

     dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) 

     return (data, response, error) 
    } 
} 

Update für Swift 3:

extension URLSession { 
    func synchronousDataTask(with url: URL) -> (Data?, URLResponse?, Error?) { 
     var data: Data? 
     var response: URLResponse? 
     var error: Error? 

     let semaphore = DispatchSemaphore(value: 0) 

     let dataTask = self.dataTask(with: url) { 
      data = $0 
      response = $1 
      error = $2 

      semaphore.signal() 
     } 
     dataTask.resume() 

     _ = semaphore.wait(timeout: .distantFuture) 

     return (data, response, error) 
    } 
} 
+1

Ich habe diese Erweiterung am Ende meiner Datei hinzugefügt und ersetzt 'NSURLSession.sharedSession(). DataTaskWithURL (URL)' mit 'NSURLSession.sharedSession(). SynchroneDataTaskWithURL (URL)', aber ich bekomme einen Fehler, dass es gibt ein zusätzliches Argument beim Aufruf. Was ist der richtige Weg, diese Erweiterungsfunktion aufzurufen? – tylerSF

+2

Was Sie geschrieben haben, ist der richtige Weg, es zu nennen, wahrscheinlich liegt der Fehler anderswo. Können Sie mehr Kontext bereitstellen? –

+1

Das zusätzliche Argument ist der Beendigungshandler, der im synchronen Aufruf nicht mehr parametrisiert werden muss. Der Aufruf dieser Methode sollte wie folgt aussehen (vorausgesetzt, Sie haben die erforderlichen Variablen deklariert): '(Daten, Antwort, Fehler) = NSURLSession.sharedSession(). SyncronicDataTaskWithURL (URL)' – dave

7

Eine der Antworten wurde aktualisiert, um stattdessen eine URLRequest zu verwenden, sodass wir stattdessen PUT usw. verwenden können.

extension URLSession { 
    func synchronousDataTask(urlrequest: URLRequest) -> (data: Data?, response: URLResponse?, error: Error?) { 
     var data: Data? 
     var response: URLResponse? 
     var error: Error? 

     let semaphore = DispatchSemaphore(value: 0) 

     let dataTask = self.dataTask(with: urlrequest) { 
      data = $0 
      response = $1 
      error = $2 

      semaphore.signal() 
     } 
     dataTask.resume() 

     _ = semaphore.wait(timeout: .distantFuture) 

     return (data, response, error) 
    } 
} 

Ich rufe so an.

var request = URLRequest(url: url1) 
request.httpBody = body 
request.httpMethod = "PUT" 
let (_, _, error) = URLSession.shared.synchronousDataTask(urlrequest: request) 
if let error = error { 
    print("Synchronous task ended with error: \(error)") 
} 
else { 
    print("Synchronous task ended without errors.") 
} 
Verwandte Themen