Comment analyser la réponse JSON de l'API Alamofire dans Swift?

125

Après le code que j'ai écrit et j'obtiens également une réponse en JSON, mais le type de JSON est "AnyObject" et je ne peux pas le convertir en Array pour pouvoir l'utiliser.

Alamofire.request(.POST, "MY URL", parameters:parameters, encoding: .JSON) .responseJSON
{
    (request, response, JSON, error) in

    println(JSON?)
}
Développeur
la source
Je n'ai pas voté contre votre question, mais je suppose que c'est parce que l'analyse de JSON est un sujet trop vaste pour donner une réponse claire et directe. Essayez cette bibliothèque appelée SwiftyJSON .
Isuru
@Isuru c'est OK! J'ai vu cette bibliothèque mais j'utilise Alamofire! Mais pouvez-vous m'envoyer l'exemple de code dans lequel vous avez utilisé le SwiftyJson? Le code ne fonctionne pas pour moi!
Développeur
J'utilise aussi SwiftyJSON avec Alamofire. Je passe juste la réponse comme ça let data = JSONValue(JSON!). Ensuite, je peux extraire des valeurs comme celle-ci data["Id"]. La documentation SwiftyJSON fournit des exemples sur la façon de récupérer ces valeurs dans les types souhaités. Quelle est exactement l'erreur que vous obtenez?
Isuru

Réponses:

160

La réponse pour Swift 2.0 Alamofire 3.0 devrait en fait ressembler davantage à ceci:

Alamofire.request(.POST, url, parameters: parameters, encoding:.JSON).responseJSON
{ response in switch response.result {
                case .Success(let JSON):
                    print("Success with JSON: \(JSON)")

                    let response = JSON as! NSDictionary

                    //example if there is an id
                    let userId = response.objectForKey("id")!

                case .Failure(let error):
                    print("Request failed with error: \(error)")
                }
    }

https://github.com/Alamofire/Alamofire/blob/master/Documentation/Alamofire%203.0%20Migration%20Guide.md

MISE À JOUR pour Alamofire 4.0 et Swift 3.0:

Alamofire.request(url, method: .post, parameters: parameters, encoding: JSONEncoding.default)
            .responseJSON { response in
                print(response)
//to get status code
                if let status = response.response?.statusCode {
                    switch(status){
                    case 201:
                        print("example success")
                    default:
                        print("error with response status: \(status)")
                    }
                }
//to get JSON return value
            if let result = response.result.value {
                let JSON = result as! NSDictionary
                print(JSON)
            }

        }
Joseph Geraghty
la source
13
Comment obtenez-vous le contenu réel de JSON? De quel type d'objet s'agit-il? La conception et la documentation sont si obscures que je ne peux pas le comprendre et je ne peux pas trouver d'exemples sur Internet ...
Alex Worden
J'ai ajouté quelques lignes dans ma réponse qui devraient aider.
Joseph Geraghty
@JosephGeraghty ayant le paramètre d'encodage, le compilateur me dit qu'il y a un appel d'argument supplémentaire ... Une idée?
amariduran
@ jch-duran n'est pas positif, mais je me souviens vaguement d'avoir rencontré quelque chose de similaire il y a quelque temps. Je pense que cela avait quelque chose à voir avec les bibliothèques qui n'étaient pas mises à jour ou peut-être pas à jour avec la version swift. S'assurer que vous êtes sur les dernières versions peut aider
Joseph Geraghty
1
@AlexWorden est d'accord, cette page m'a aidé à répondre à ces questions et fournit une solution intéressante: github.com/SwiftyJSON/SwiftyJSON
iljn
31

comme mentionné ci-dessus, vous pouvez utiliser la bibliothèque SwiftyJSON et obtenir vos valeurs comme je l'ai fait ci-dessous

Alamofire.request(.POST, "MY URL", parameters:parameters, encoding: .JSON) .responseJSON
{
    (request, response, data, error) in

var json = JSON(data: data!)

       println(json)   
       println(json["productList"][1])                 

}

mon retour de liste de produits json du script

{ "productList" :[

{"productName" : "PIZZA","id" : "1","productRate" : "120.00","productDescription" : "PIZZA AT 120Rs","productImage" : "uploads\/pizza.jpeg"},

{"productName" : "BURGER","id" : "2","productRate" : "100.00","productDescription" : "BURGER AT Rs 100","productImage" : "uploads/Burgers.jpg"}    
  ]
}

production :

{
  "productName" : "BURGER",
  "id" : "2",
  "productRate" : "100.00",
  "productDescription" : "BURGER AT Rs 100",
  "productImage" : "uploads/Burgers.jpg"
}
Vikram Pote
la source
J'essaie d'utiliser le truc SwiftyJson après l'installation, mais donne environ 300 erreurs dans le fichier SwiftyJson, est-ce que quelqu'un a rencontré le problème? i ', en utilisant Xcode version 6.2, ios version 8.1, cocoaPods 36 comme mentionné dans la documentation [github] ( github.com/SwiftyJSON/SwiftyJSON ).
Sashi
2
Mec. Quelles sont les erreurs? Posez une question distincte et fournissez quelques détails. SwiftyJSON est aussi beau que magique. Utilisez-le si possible.
Zia
Vraiment devrait convertir la chaîne json en un objet rapide concret afin que vous puissiez l'utiliser proprement de manière naturelle. Accéder aux champs par leur nom de chaîne est ridicule et sujet aux erreurs.
The Muffin Man
26

Swift 3, Alamofire 4.4 et SwiftyJSON:

Alamofire.request(url, method: .get)
  .responseJSON { response in
      if response.data != nil {
        let json = JSON(data: response.data!)
        let name = json["people"][0]["name"].string
        if name != nil {
          print(name!)
        }
      }
  }

Cela analysera cette entrée JSON:

{
  people: [
    { name: 'John' },
    { name: 'Dave' }
  ]
}
iljn
la source
Il existe également un plugin spécifique à Alamofire Swifty-JSON qui supprime la nécessité de la JSON()conversion explicite : github.com/SwiftyJSON/Alamofire-SwiftyJSON
Robin Macharg
Cela m'aide, mais j'ai eu quelques problèmes avec la méthode JSON car jette une exception
iGhost
24

J'ai trouvé la réponse sur GitHub pour Swift2

https://github.com/Alamofire/Alamofire/issues/641

Alamofire.request(.GET, URLString, parameters: ["foo": "bar"])
    .responseJSON { request, response, result in
        switch result {
        case .Success(let JSON):
            print("Success with JSON: \(JSON)")

        case .Failure(let data, let error):
            print("Request failed with error: \(error)")

            if let data = data {
                print("Response data: \(NSString(data: data, encoding: NSUTF8StringEncoding)!)")
            }
        }
    }
mick80234
la source
3
Il s'agit d'une version correcte pour l'analyse Swift 2.0 + Alamofire JSON.
Saqib Omer
5
hmm je reçois toujours un échec construit un message d'erreur: '(_, _, _) -> Void' n'est pas convertible en 'Response <AnyObject, NSError> -> Void'
alex
@alex Voir cette réponse pour ce que j'ai utilisé pour le résoudre.
Joseph
Merci beaucoup ! Vous n'avez aucune idée du nombre de choses que j'ai essayé d'afficher correctement le message de réponse du serveur, sauveur de la vie!
thibaut noah
17

Je ne suis ni un expert JSON ni un expert Swift, mais ce qui suit fonctionne pour moi. :) J'ai extrait le code de mon application actuelle, et seulement changé "MyLog en println", et mis en retrait avec des espaces pour qu'il s'affiche sous forme de bloc de code (j'espère que je ne l'ai pas cassé).

func getServerCourseVersion(){

    Alamofire.request(.GET,"\(PUBLIC_URL)/vtcver.php")
        .responseJSON { (_,_, JSON, _) in
          if let jsonResult = JSON as? Array<Dictionary<String,String>> {
            let courseName = jsonResult[0]["courseName"]
            let courseVersion = jsonResult[0]["courseVersion"]
            let courseZipFile = jsonResult[0]["courseZipFile"]

            println("JSON:    courseName: \(courseName)")
            println("JSON: courseVersion: \(courseVersion)")
            println("JSON: courseZipFile: \(courseZipFile)")

          }
      }
}

J'espère que cela t'aides.

Éditer:

Pour référence, voici ce que mon script PHP renvoie:

[{"courseName": "Training Title","courseVersion": "1.01","courseZipFile": "101/files.zip"}]
KenL
la source
Cela devrait être la réponse sélectionnée, bien que vous souhaitiez peut-être la mettre à jour car Alamofire a mis à jour un peu ses méthodes
Snymax
10

rapide 3

pod 'Alamofire', '~> 4.4'
pod 'SwiftyJSON'

File json format:
{
    "codeAd": {
        "dateExpire": "2017/12/11",
        "codeRemoveAd":"1231243134"
        }
}

import Alamofire
import SwiftyJSON
    private func downloadJson() {
        Alamofire.request("https://yourlinkdownloadjson/abc").responseJSON { response in
            debugPrint(response)

            if let json = response.data {
                let data = JSON(data: json)
                print("data\(data["codeAd"]["dateExpire"])")
                print("data\(data["codeAd"]["codeRemoveAd"])")
            }
        }
    }
Giang
la source
2

J'ai trouvé un moyen de convertir le response.result.value (à l'intérieur d'une fermeture Alamofire responseJSON) au format JSON que j'utilise dans mon application.

J'utilise Alamofire 3 et Swift 2.2.

Voici le code que j'ai utilisé:

    Alamofire.request(.POST, requestString,
                      parameters: parameters,
                      encoding: .JSON,
                      headers: headers).validate(statusCode: 200..<303)
                                       .validate(contentType: ["application/json"])
                                       .responseJSON { (response) in
        NSLog("response = \(response)")

        switch response.result {
        case .Success:
            guard let resultValue = response.result.value else {
                NSLog("Result value in response is nil")
                completionHandler(response: nil)
                return
            }

            let responseJSON = JSON(resultValue)

            // I do any processing this function needs to do with the JSON here

            // Here I call a completionHandler I wrote for the success case
        break
        case .Failure(let error):
            NSLog("Error result: \(error)")
            // Here I call a completionHandler I wrote for the failure case
            return
        }
Carl Smith
la source
2

J'utilise généralement la bibliothèque Gloss pour sérialiser ou désérialiser JSON dans iOS. Par exemple, j'ai JSON qui ressemble à ceci:

{"ABDC":[{"AB":"qwerty","CD":"uiop"}],[{"AB":"12334","CD":"asdf"}]}

Tout d'abord, je modélise le tableau JSON dans la structure Gloss:

Struct Struct_Name: Decodable {
   let IJ: String?
   let KL: String?
   init?(json: JSON){
       self.IJ = "AB" <~~ json
       self.KL = "CD" <~~ json
   }
}

Et puis dans Alamofire responseJSON, je fais la chose suivante:

Alamofire.request(url, method: .get, paramters: parametersURL).validate(contentType: ["application/json"]).responseJSON{ response in
 switch response.result{
   case .success (let data):
    guard let value = data as? JSON,
       let eventsArrayJSON = value["ABDC"] as? [JSON]
    else { fatalError() }
    let struct_name = [Struct_Name].from(jsonArray: eventsArrayJSON)//the JSON deserialization is done here, after this line you can do anything with your JSON
    for i in 0 ..< Int((struct_name?.count)!) {
       print((struct_name?[i].IJ!)!)
       print((struct_name?[i].KL!)!)
    }
    break

   case .failure(let error):
    print("Error: \(error)")
    break
 }
}

La sortie du code ci-dessus:

qwerty
uiop
1234
asdf
Luthfi Rahman
la source
2

Swift 5

class User: Decodable {

    var name: String
    var email: String
    var token: String

    enum CodingKeys: String, CodingKey {
        case name
        case email
        case token
    }

    public required init(from decoder: Decoder) throws {
        let container = try decoder.container(keyedBy: CodingKeys.self)
        self.name = try container.decode(String.self, forKey: .name)
        self.email = try container.decode(String.self, forKey: .email)
        self.token = try container.decode(String.self, forKey: .token)
    }
}

API Alamofire

    Alamofire.request("url.endpoint/path", method: .get, parameters: params, encoding: URLEncoding.queryString, headers: nil)
     .validate()
     .responseJSON { response in

        switch (response.result) {

            case .success( _):

            do {
                let users = try JSONDecoder().decode([User].self, from: response.data!)
                print(users)

            } catch let error as NSError {
                print("Failed to load: \(error.localizedDescription)")
            }

             case .failure(let error):
                print("Request error: \(error.localizedDescription)")
         }
Sazzad Hissain Khan
la source
1

Cela a été construit avec Xcode 10.1 et Swift 4

Combinaison parfaite "Alamofire" (4.8.1) et "SwiftyJSON" (4.2.0). Vous devez d'abord installer les deux pods

pod 'Alamofire' et pod 'SwiftyJSON'

La réponse du serveur au format JSON:

{
  "args": {}, 
  "headers": {
    "Accept": "*/*", 
    "Accept-Encoding": "gzip;q=1.0, compress;q=0.5", 
    "Accept-Language": "en;q=1.0", 
    "Host": "httpbin.org", 
    "User-Agent": "AlamoFire TEST/1.0 (com.ighost.AlamoFire-TEST; build:1; iOS 12.1.0) Alamofire/4.8.1"
  }, 
  "origin": "200.55.140.181, 200.55.140.181", 
  "url": "https://httpbin.org/get"
}

Dans ce cas, je veux imprimer les informations "Host": "Host": "httpbin.org"

Alamofire.request("https://httpbin.org/get").validate().responseJSON { response in
        switch response.result {
        case .success:
            print("Validation Successful)")

            if let json = response.data {
                do{
                    let data = try JSON(data: json)
                    let str = data["headers"]["Host"]
                    print("DATA PARSED: \(str)")
                }
                catch{
                print("JSON Error")
                }

            }
        case .failure(let error):
            print(error)
        }
    }

Gardez le code calme et heureux 😎

iGhost
la source
0

dans swift 5, nous aimons utiliser des typealias pour la complétion. Typlealias rien n'utilise juste pour nettoyer le code.

typealias response = (Bool,Any?)->()


static func postCall(_ url : String, param : [String : Any],completion : @escaping response){
    Alamofire.request(url, method: .post, parameters: param, encoding: JSONEncoding.default, headers: [:]).responseJSON { (response) in

        switch response.result {
           case .success(let JSON):
               print("\n\n Success value and JSON: \(JSON)")

           case .failure(let error):
               print("\n\n Request failed with error: \(error)")

           }
    }
}
Talha Rasool
la source
-10
 pod 'Alamofire'
 pod 'SwiftyJSON'
 pod 'ReachabilitySwift'



import UIKit
import Alamofire
import SwiftyJSON
import SystemConfiguration

class WebServiceHelper: NSObject {

    typealias SuccessHandler = (JSON) -> Void
    typealias FailureHandler = (Error) -> Void

    // MARK: - Internet Connectivity

    class func isConnectedToNetwork() -> Bool {

        var zeroAddress = sockaddr_in()
        zeroAddress.sin_len = UInt8(MemoryLayout<sockaddr_in>.size)
        zeroAddress.sin_family = sa_family_t(AF_INET)

        guard let defaultRouteReachability = withUnsafePointer(to: &zeroAddress, {
            $0.withMemoryRebound(to: sockaddr.self, capacity: 1) {
                SCNetworkReachabilityCreateWithAddress(nil, $0)
            }
        }) else {
            return false
        }

        var flags: SCNetworkReachabilityFlags = []
        if !SCNetworkReachabilityGetFlags(defaultRouteReachability, &flags) {
            return false
        }

        let isReachable = flags.contains(.reachable)
        let needsConnection = flags.contains(.connectionRequired)

        return (isReachable && !needsConnection)
    }

    // MARK: - Helper Methods

    class func getWebServiceCall(_ strURL : String, isShowLoader : Bool, success : @escaping SuccessHandler, failure : @escaping FailureHandler)
    {
        if isConnectedToNetwork() {

            print(strURL)

            if isShowLoader == true {

                AppDelegate.getDelegate().showLoader()
            }

            Alamofire.request(strURL).responseJSON { (resObj) -> Void in

                print(resObj)

                if resObj.result.isSuccess {
                    let resJson = JSON(resObj.result.value!)

                    if isShowLoader == true {
                        AppDelegate.getDelegate().dismissLoader()
                    }

                    debugPrint(resJson)
                    success(resJson)
                }
                if resObj.result.isFailure {
                    let error : Error = resObj.result.error!

                    if isShowLoader == true {
                        AppDelegate.getDelegate().dismissLoader()
                    }
                    debugPrint(error)
                    failure(error)
                }
            }
        }else {


            CommonMethods.showAlertWithError("", strMessage: Messages.NO_NETWORK, withTarget: (AppDelegate.getDelegate().window!.rootViewController)!)
        }
    }

    class func getWebServiceCall(_ strURL : String, params : [String : AnyObject]?, isShowLoader : Bool, success : @escaping SuccessHandler,  failure :@escaping FailureHandler){
        if isConnectedToNetwork() {

            if isShowLoader == true {
                AppDelegate.getDelegate().showLoader()
            }


            Alamofire.request(strURL, method: .get, parameters: params, encoding: JSONEncoding.default, headers: nil).responseJSON(completionHandler: {(resObj) -> Void in

                print(resObj)

                if resObj.result.isSuccess {
                    let resJson = JSON(resObj.result.value!)

                    if isShowLoader == true {
                        AppDelegate.getDelegate().dismissLoader()
                    }

                    success(resJson)
                }
                if resObj.result.isFailure {
                    let error : Error = resObj.result.error!

                    if isShowLoader == true {
                        AppDelegate.getDelegate().dismissLoader()
                    }

                    failure(error)
                }

            })
        }
    else {

            CommonMethods.showAlertWithError("", strMessage: Messages.NO_NETWORK, withTarget: (AppDelegate.getDelegate().window!.rootViewController)!)
    }

    }



    class func postWebServiceCall(_ strURL : String, params : [String : AnyObject]?, isShowLoader : Bool, success : @escaping SuccessHandler, failure :@escaping FailureHandler)
    {
        if isConnectedToNetwork()
        {

            if isShowLoader == true
            {
                AppDelegate.getDelegate().showLoader()
            }

            Alamofire.request(strURL, method: .post, parameters: params, encoding: JSONEncoding.default, headers: nil).responseJSON(completionHandler: {(resObj) -> Void in

                print(resObj)

                if resObj.result.isSuccess
                {
                    let resJson = JSON(resObj.result.value!)

                    if isShowLoader == true
                    {
                        AppDelegate.getDelegate().dismissLoader()
                    }

                    success(resJson)
                }

                if resObj.result.isFailure
                {
                    let error : Error = resObj.result.error!

                    if isShowLoader == true
                    {
                        AppDelegate.getDelegate().dismissLoader()
                    }

                    failure(error)
                }
            })
        }else {
            CommonMethods.showAlertWithError("", strMessage: Messages.NO_NETWORK, withTarget: (AppDelegate.getDelegate().window!.rootViewController)!)
        }
    }


    class func postWebServiceCallWithImage(_ strURL : String, image : UIImage!, strImageParam : String, params : [String : AnyObject]?, isShowLoader : Bool, success : @escaping SuccessHandler, failure : @escaping FailureHandler)
    {
        if isConnectedToNetwork() {
            if isShowLoader == true
            {
                AppDelegate.getDelegate().showLoader()
            }

            Alamofire.upload(
                multipartFormData: { multipartFormData in
                    if let imageData = UIImageJPEGRepresentation(image, 0.5) {
                        multipartFormData.append(imageData, withName: "Image.jpg")
                    }

                    for (key, value) in params! {

                        let data = value as! String

                        multipartFormData.append(data.data(using: String.Encoding.utf8)!, withName: key)
                        print(multipartFormData)
                    }
                },
                to: strURL,
                encodingCompletion: { encodingResult in
                    switch encodingResult {
                    case .success(let upload, _, _):
                        upload.responseJSON { response in
                            debugPrint(response)
                            //let datastring = String(data: response, encoding: String.Encoding.utf8)
                           // print(datastring)
                        }
                    case .failure(let encodingError):
                        print(encodingError)
                        if isShowLoader == true
                        {
                            AppDelegate.getDelegate().dismissLoader()
                        }

                        let error : NSError = encodingError as NSError
                        failure(error)
                    }

                    switch encodingResult {
                    case .success(let upload, _, _):
                        upload.responseJSON { (response) -> Void in

                            if response.result.isSuccess
                            {
                                let resJson = JSON(response.result.value!)

                                if isShowLoader == true
                                {
                                    AppDelegate.getDelegate().dismissLoader()
                                }

                                success(resJson)
                            }

                            if response.result.isFailure
                            {
                                let error : Error = response.result.error! as Error

                                if isShowLoader == true
                                {
                                    AppDelegate.getDelegate().dismissLoader()
                                }

                                failure(error)
                            }

                        }
                    case .failure(let encodingError):
                        if isShowLoader == true
                        {
                            AppDelegate.getDelegate().dismissLoader()
                        }

                        let error : NSError = encodingError as NSError
                        failure(error)
                    }
                }
            )
        }
        else
        {
            CommonMethods.showAlertWithError("", strMessage: Messages.NO_NETWORK, withTarget: (AppDelegate.getDelegate().window!.rootViewController)!)
        }
    }

}


==================================


Call Method


let aParams : [String : String] = [
                "ReqCode" : Constants.kRequestCodeLogin,
                ]

            WebServiceHelper.postWebServiceCall(Constants.BaseURL, params: aParams as [String : AnyObject]?, isShowLoader: true, success: { (responceObj) in


                if "\(responceObj["RespCode"])" != "1"
                {
                    let alert = UIAlertController(title: Constants.kAppName, message: "\(responceObj["RespMsg"])", preferredStyle: UIAlertControllerStyle.alert)
                    let OKAction = UIAlertAction(title: "OK", style: .default) { (action:UIAlertAction!) in
                    }
                    alert.addAction(OKAction)
                    self.present(alert, animated: true, completion: nil)
                }
                else
                {
                    let aParams : [String : String] = [
                        "Password" : self.dictAddLogin[AddLoginConstants.kPassword]!,
                        ]
                    CommonMethods.saveCustomObject(aParams as AnyObject?, key: Constants.kLoginData)

                }
                }, failure:
                { (error) in

                    CommonMethods.showAlertWithError(Constants.kALERT_TITLE_Error, strMessage: error.localizedDescription,withTarget: (AppDelegate.getDelegate().window!.rootViewController)!)
            })
        }
Nikunj Patel
la source
6
Une explication de tout ce code serait utile.
peter.swallow