2017-03-09 1 views
4

Je reçois des problèmes très similaires à this post, mais je ne comprends pas complètement la réponse. J'ai créé un gestionnaire d'achèvement, mais il ne semble pas fonctionner comme prévu.Swift URL Session et URL Demande ne fonctionne pas

func updateTeam(teamID: Int) { 
    startConnection {NSArray, Int in 
     //Do things with NSArray 
    } 
} 

func startConnection(completion: (NSArray, Int) -> Void) { 
    let url = URL(string: "http://www.example.com/path") 
    var request : URLRequest = URLRequest(url: url!) 
    request.httpMethod = "POST" 
    let postString = "a=\(Int(teamInput.text!)!)" 
    request.httpBody = postString.data(using: .utf8) 

    let dataTask = URLSession.shared.dataTask(with: request) { 
     data,response,error in 
     print("anything") 
     do { 
      if let jsonResult = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary { 
       self.teamResult = jsonResult 
       print(jsonResult) 
      } 
     } catch let error as NSError { 
      print(error.localizedDescription) 
     } 

    } 
    dataTask.resume() 

    completion(NSArray(object: teamResult), Int(teamInput.text!)!) 
} 

Rien dans la déclaration dataTask semble fonctionner, ou du moins il ne se termine pas avant d'essayer d'utiliser les données ont donné lieu. Quel est le problème avec ce gestionnaire d'achèvement?

Merci d'avance!

+0

Je pense que 'achèvement (NSArray (objet: teamResult), Int (teamInput.text!)!) 'devrait aller là où vous avez' print (jsonResult) '. Comme c'est le cas maintenant, vous démarrez la tâche de données, puis appelez immédiatement le gestionnaire d'achèvement avec (probablement) 'nil'. Si vous définissez un point d'arrêt dans votre gestionnaire de datatask (sur l'une des méthodes d'impression), les points d'arrêt sont-ils atteints? – keithbhunter

+1

Je vous recommande fortement de rechercher Alamofire et l'utiliser si vous le pouvez pour ce projet, il rend le code comme cela beaucoup plus facile à écrire –

+0

oui, déplacer le gestionnaire de la tâche de données a semblé fonctionner magnifiquement. Merci beaucoup! –

Répondre

3

Votre code est structuré de façon incorrecte.

URLSession crée des tâches qui sont exécutées de manière asynchrone. Vous définissez une tâche et transmettez un bloc d'achèvement ou définissez un délégué.

L'appel task.resume() renvoie immédiatement, bien avant que le téléchargement réseau soit terminé.

Une fois la tâche terminée, le système appelle votre gestionnaire d'achèvement (ou votre délégué, si vous utilisez le style délégué).

Notez que les gestionnaires d'achèvement URLSessions et les appels délégués sont effectués sur un thread d'arrière-plan. Si vous effectuez des appels UIKit en réponse à une tâche, vous devez le faire sur le thread principal. Comme dit @keithbhunter dans son commentaire, vous devez placer l'appel à votre gestionnaire de complétion dans le gestionnaire de complétion de votre tâche. Il est probablement plus sûr si vous enveloppez que tout appel de gestionnaire d'achèvement dans un appel au thread principal:

func startConnection(completion: (NSArray, Int) -> Void) { 
    let url = URL(string: "http://www.example.com/path") 
    var request : URLRequest = URLRequest(url: url!) 
    request.httpMethod = "POST" 
    let postString = "a=\(Int(teamInput.text!)!)" 
    request.httpBody = postString.data(using: .utf8) 

    let dataTask = URLSession.shared.dataTask(with: request) { 
     data,response,error in 
     print("anything") 
     do { 
      if let jsonResult = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary { 
       self.teamResult = jsonResult 
       print(jsonResult) 
       //Use GCD to invoke the completion handler on the main thread 
       DispatchQueue.main.async() { 
        completion(NSArray(object: teamResult), Int(teamInput.text!)!) 
       } 
      } 
     } catch let error as NSError { 
      print(error.localizedDescription) 
     } 
    } 
    dataTask.resume() 
} 

Notez que votre force de dépliage teamInput.text est très fragile, et se bloque si teamInput.text est nul, ou s'il ne peut pas être converti en Int. Vous seriez bien mieux d'écrire votre gestionnaire d'achèvement à prendre pour les optionals les données et la valeur int vous revenez de teamInput.text:

func startConnection(completion: (NSArray?, Int?) -> Void) { 

et appelez le passage dans une option:

let value: Int? = teamInput.text != nil ? Int(teamInput.text!) : nil 
completion(NSArray(object: teamResult), value) 
2

Je pense que vous devriez également gérer l'erreur à la fermeture.

func updateTeam(teamID: Int) { 
    startConnection {array, teamId, error in 
     // Do things with NSArray or handle error 
    } 
} 

func startConnection(completion: @escaping (NSArray?, Int, Error?) -> Void) { 
    let url = URL(string: "http://www.example.com/path") 
    var request : URLRequest = URLRequest(url: url!) 
    request.httpMethod = "POST" 
    let postString = "a=\(Int(teamInput.text!)!)" 
    request.httpBody = postString.data(using: .utf8) 

    let dataTask = URLSession.shared.dataTask(with: request) { 
     data,response,error in 
     print("anything") 
     do { 
      if let jsonResult = try JSONSerialization.jsonObject(with: data!, options: []) as? NSDictionary { 
       self.teamResult = jsonResult 
       print(jsonResult) 
       DispatchQueue.main.async() { 
        completion(NSArray(object: self.teamResult), Int(teamInput.text!)!, nil) 
       } 
     } catch let error as NSError { 
      print(error.localizedDescription) 
      DispatchQueue.main.async() { 
       completion(nil, Int(teamInput.text!)!, error) 
      } 
     } 

    } 
    dataTask.resume() 
} 
+0

Notez que l'OP dépliant force de teamInput est également dangereux. Voir ma réponse ... –

0

Essayez ceci:

let urlString = "www.yoururl.com" 
let url = URL(string: string.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed)!) 

cela a aidé pour moi beaucoup de fois