2016-07-01 1 views
0

Dans ce code, request.getStatusCode() et request.getIsConnected() à la fois exécuter avant que le code à l'intérieur du bloc task est exécutéSwift 2 Comment puis-je attendre NSURLSessionDataTask pour terminer avant le code continue

-à-dire dataTask.resume() n'exécute qu'après tout code suivant est exécuté, qu'il s'agisse de code dans la même fonction, classe ou classe distincte.

J'ai essayé de placer l'appel de fonction dans la file d'attente principale (sérielle), une file d'attente globale (simultanée), une file d'attente série manuelle, une file d'attente manuelle simultanée et une file d'attente NSOperationQueue la fermeture est terminée.

while isDoingSomething { 
    NSThread.sleepForTimeInterval(0.0) 
} 

boucle.

J'ai laissé des GCD ou des opérations hors de ce code pour éviter l'encombrement de chaque scénario de file d'attente que j'ai essayé.

ViewController.swift

import Cocoa 
class ViewController: NSViewController { 
    . 
    . 
    . 
    func login(username username: String, password: String) { 
     let url = "https://www.awebsite.com/login" 
     let URL = NSURL(string: url) 
     let method = "POST" 
     let params = "username=\(username)&password=\(password)" 
     vis = URLVisitor(URL: URL!, params: params, method: method, jsonParams: [:]) 
     vis.execute() 
     cookies = vis.getCookies() 
     let contentsOfURL = vis.getContentsOfURL() 
    } 
    . 
    . 
    . 
} 

URLVisitor.swift

import Cocoa 
let queue = NSOperationQueue 

class URLVisitor: NSOperation { 
    . 
    . 
    . 

    func execute() { 
     let request = Request(URL: URL!, params: params, method: method, jsonParams: jsonParams) 
     if !self.cookies.isEmpty { 
      request._setCookies(self.cookies) 
     } 

     request._setAuthorizationHeader(self.authorizationHeader) 
     request.sendRequest() 

     self.statusCode = request.getStatusCode() 
     self.isConnected = request.getIsConnected() 
    } 
    . 
    . 
    . 

} 

Request.swift

import Cocoa 
class Request: NSOperation { 
    . 
    . 
    . 

    func sendRequest() { 
     let session = NSURLSession.sharedSession() 
     let request = NSMutableURLRequest(URL: URL) 
     request.HTTPMethod = method 

     // send jsonParams or params 
     if jsonParams.count != 0 { 
      do { 
       let jsonData = try NSJSONSerialization.dataWithJSONObject(jsonParams, options: .PrettyPrinted) 

       request.setValue("aplication/json; charset=utf-8", forHTTPHeaderField: "Content-Type") 
       request.HTTPBody = jsonData 
      } catch { 
     } 
    } else { 
     request.HTTPBody = self.params.dataUsingEncoding(NSUTF8StringEncoding) 
    } 
    let task = session.dataTaskWithRequest(request) { 
     (data, response, error) in 

    NSHTTPCookieStorage.sharedHTTPCookieStorage().setCookies(self.cookies, forURL: self.URL, mainDocumentURL: nil) 
     if data != nil { 
      self.data = data! 
      do { 
       let responseHeaders = response as! NSHTTPURLResponse 
       self.statusCode = responseHeaders.statusCode 

       switch self.statusCode { 
        case 200: 
         print("200: OK. getting contentsOfURL and cookies") 
         self.contentsOfURL = try NSString(contentsOfURL: self.URL, encoding: NSUTF8StringEncoding) 
         self.cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage().cookiesForURL(self.URL)! 

        case 400: 
         print("400: page not found on web") 

        case 404: 
         print("404: page not found on server") 

        case 407: 
         print("407: failed authenticate proxy credentials") 

        default: 
         print("unable to get statusCode") 
       } 
      } catch { 

      } 
     } else { 
      print("\(self.statusCode): unable to get response ") 
     } 
     NSThread.sleepForTimeInterval(1.0) 
    } 
    task.resume() 
} 
+0

L'attente de l'achèvement d'une tâche asynchrone en utilisant 'while' et' sleep' est horrible. Apprenez à comprendre le comportement asynchrone des 'tâches' de' NSURLSession.' Par exemple mettre les deux fonctions dans le bloc d'achèvement. – vadian

+0

Merci. Crois moi; Je sais qu'une boucle est horrible. C'est pourquoi je cherche de l'aide. Mais la valeur de retour des fonctions est nécessaire pour la classe VC. Les mettre dans la fermeture de tâche n'aurait pas de sens pour moi parce que ces variables sont déjà présentes dans la classe dans laquelle se trouve la fermeture de la tâche (URLVisitor). Qu'est-ce que je rate? Pouvez-vous recommander un bon tutoriel qui explique mieux cela? – dbconfession

Répondre

1

La bonne façon de le faire est d'ajouter un gestionnaire d'achèvement

func sendRequest(completion:() -> Void) { 
    // ... 
    let task = session.dataTaskWithRequest(request) { 
     // ... 

     completion() 
    } 
    task.resume() 
} 

Utilisation:

let r = Request() 
r.sendRequest { 
    // It's done, do something 
} 

Si vous insistez pour bloquer le fil (je l'espère ce n'est pas le thread principal), utilisez un sémaphores. Mais n'oubliez pas de signaler au sémaphore si la requête a réussi ou échoué. J'ai vu beaucoup trop de code qui a oublié de signaler le sémaphore quand la requête échoue, alors l'application a simplement raccroché.

func sendRequest() { 
    let semaphore = dispatch_semaphore_create(0) 

    let task = session.dataTaskWithRequest(request) { 
     // ... 
     dispatch_semaphore_signal(semaphore) 
    } 
    task.resume() 
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER) 
}