json parser

Bonsoir à  tous,


 


Selon vous pourquoi je n'arrive pas à  récupérer les valeurs que je parse à  l'aide cette fonction :



class produit {
var nomProduit = String()

init() {
...
}

func jParser(id: String) -> String {

let urlPath = " "
let endpoint = NSURL(string: urlPath)
let request = NSMutableURLRequest(URL:endpoint!)
/*
let qualityOfServiceClass = QOS_CLASS_BACKGROUND
let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
dispatch_async(backgroundQueue, {
*/
NSURLSession.sharedSession().dataTaskWithRequest(request) { (data, response, error) -> Void in
do {
guard let dat = data else { throw JSONError.NoData }
guard let json = try NSJSONSerialization.JSONObjectWithData(dat, options: []) as? NSDictionary else { throw JSONError.ConversionFailed }
// dispatch_async(dispatch_get_main_queue(), { () -> Void in
self.nomProduit = (json[" produit "] as! String)
print(self.nomProduit)
// })
} catch let error as JSONError {
print(error.rawValue)
} catch {
print(error)
}
}.resume()
// })
return self.nomProduit
}


}

Print(self.jParser(1)) ne donne rien dans une autre classe.


le print(self.nomProduit) dans la fonction me renvoie bien le nom du produit.


 


Merci.


Réponses

  • Tu utiliser une méthode asynchrone, il faudrait donc utiliser un block (ou en Swift une closure).



  • func jParser(id: String) {

    let config = NSURLSessionConfiguration.defaultSessionConfiguration()
    let session = NSURLSession(configuration: config)
    let urlPath = " "
    let url = NSURL(string: urlPath)
    let urlRequest = NSURLRequest(URL: url!)
    let task = session.dataTaskWithRequest(urlRequest, completionHandler: { (data, response, error) in
    guard let responseData = data else {
    print("Error: did not receive data")
    return
    }
    guard error == nil else {
    print("error calling GET on /posts/1")
    print(error)
    return
    }
    let post: NSDictionary
    do {
    post = try NSJSONSerialization.JSONObjectWithData(responseData,
    options: []) as! NSDictionary
    } catch {
    print("error trying to convert data to JSON")
    return
    }
    // now we have the post, let's just print it to prove we can access it
    // print("The post is: " + post.description)
    self.nomProduit = post["Produit"] as! String

    })
    task.resume()

    }

    Même avec ce code, je ne peux pas récupérer la donnée nomProduit en dehors de jParser !


  • AliGatorAliGator Membre, Modérateur
    février 2016 modifié #4
    Comme a dit Larme:

    Tu utiliser une méthode asynchrone, il faudrait donc utiliser un block (ou en Swift une closure).

    Donc si, tu peux bien récupérer self.nomProduit en dehors de jParser. Mais faut juste pas la récupérer trop tôt (genre avant que la requête et le parsing, qui sont asynchrones, ne soit finis). Si tu attends que la requête + le parsing soient finis tu verras que tu auras la bonne valeur ensuit dans self.nomProduit. D'où l'intérêt du completionBlock pour être signalé quand cette opération asynchrone est finie justement...
  • Merci pour les informations, 


    mais cela se traduirait comment dans ma fonction le completionBlock, car j'ai du mal à  le mettre en place !


    encore merci


  • samirsamir Membre
    février 2016 modifié #6

    Hello,


     


    Il faut relire le chapitre sur les fonctions et les closures, c'est très important   :)



    func jParser(id: String, completion:(produit: String) -> ()) {

    ....
    let nomProduit = post["Produit"] as! String
    completion(produit: nomProduit)
    })
    task.resume()
    }

    Et tu pourras l'appeler comme ça :



    jParser("tonId") { (produit) -> () in
    }

    Edit : Petite explication


     


    jParser : est une fonction qui a pour paramètre un String(id) et une fonction (completion).


     


    En Swift, les fonctions sont des "first class citizen" ou "first class functions", ce qui veut dire qu'elles sont traitées comme les autres types du language, donc les fonctions supportent toutes ou presque les opérations qui s'appliquent aux autres types.


     


    On peut assigner une fonction à  une variable


    On peut passer une fonction comme paramètre ( comme ton cas)


    .....


     


    PS : Attention l'appel de la fonction jsParser est simplifié en utilisant les "training closure", c'est juste une syntaxe simplifiée sur les closures. J'aurais pu utiliser :



    WSManager.jParser("", completion: {(produit: String) -> () in
    })

    Tu comprendras mieux tout ça en lisant le chapitres sur les fonctions et closure dans le livre Swift Apple.

  • Merci beaucoup, ça marche.


    Et effectivement je vais relire la documentation sur les closures. 


  • Le principe c'est de lancer un travail en disant "quand tu auras fini, tu exécuteras ce petit bout de code".
    Le "petit bout de code" en question est situé dans la closure, il n'aura pas été exécuté quand tu sortiras de ta fonction puisque le travail de téléchargement n'aura pas encore été fait.

    Du coup, en général, on cherche un moyen de prévenir celui qui est intéressé par la fin du travail.
Connectez-vous ou Inscrivez-vous pour répondre.