web-dev-qa-db-fra.com

La session d'URL Swift et la demande d'URL ne fonctionnent pas

Je reçois des problèmes très similaires à ce post , mais je ne comprends pas bien la réponse. J'ai créé un gestionnaire d'achèvement, mais il ne semble pas fonctionner comme prévu.

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 l'instruction dataTask ne semble s'exécuter ou, du moins, il ne se termine pas avant que j'essaie d'utiliser les données obtenues. Quel est le problème avec ce gestionnaire d'achèvement?

Merci d'avance!

4
D. Cohen

Votre code est structuré de manière incorrecte. 

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

L'appel task.resume () retourne immédiatement, bien avant la fin du téléchargement sur le réseau.

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é).

Veillez à ce que les gestionnaires d'achèvement et les appels de délégués d'URLSessions soient effectués sur un thread en arrière-plan. Si vous passez des appels UIKit en réponse à l’achèvement d’une tâche, vous devez le faire sur le fil principal.

Comme @keithbhunter le dit dans son commentaire, vous devez placer l'appel dans votre gestionnaire d'achèvement dans le gestionnaire d'achèvement de votre tâche. C'est probablement le plus sûr si vous intégrez tout cet appel du 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 décompression forcée de teamInput.text est très fragile et se bloquera si teamInput.text a la valeur nil ou s'il ne peut pas être converti en Int. Vous feriez bien mieux d'écrire votre gestionnaire d'achèvement afin de prendre des options pour les données et la valeur int que vous récupérez de teamInput.text:

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

et appelez-le en passant en option:

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

Je pense que vous devriez également gérer les erreurs lors de 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()
}
2
abdullahselek

Essaye ça:

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

Cela m'a aidé beaucoup de fois

0
Fri3ndlyGerman