Group Group Group Group Group Group Group Group Group

Why can not I download this JSON?

#1

Hi all!
I have a problem when downloading data from this JSON via PHP server and MySQL, and the data is shown as Nil.

{
    "status": "400",
    "message": "Usuario ya registrado",
    "result": [
        {
            "id_UsuariosClientes": 4,
            "nombreCliente": "Rodrigo",
            "apesCliente": "Sanchez",
            "numeroTarjeta": null,
            "noTarjetaRegalo": 146352927,
            "nomUsuarioCliente": null,
            "psswdUsuarioCliente": null,
            "mailUsuarioCliente": "rocky_saco@hotmail.es",
            "telUsuarioCliente": "9931823166",
            "tipoTarjetaCliente": null,
            "fotoClienteUsuario": null,
            "registroCliente": "2019-05-08 17:31:12",
            "cumpleCliente": "1990-10-26",
            "salt": null,
            "tipoRegistro": null,
            "numeroLealtad": 234679822
        }
    ]
}

I do not know if the method I’m downloading is correct.

import UIKit
import FBSDKLoginKit

struct Response: Codable {
    var status : String
    var message: String
    let result: [Result]
}

struct Result: Codable {
    let idUsuariosClientes: Int
    let nombreCliente, apesCliente: String
    let numeroTarjeta, tarjetaRegaloCliente: Int
    let nomUsuarioCliente: String
    let mailUsuarioCliente: String
    let telUsuarioCliente: Int
    let tipoTarjetaCliente: String
    let registroCliente, cumpleCliente: String
    let tipoRegistro: String
    
    enum CodingKeys: String, CodingKey {
        case idUsuariosClientes = "id_UsuariosClientes"
        case nombreCliente, apesCliente, numeroTarjeta, tarjetaRegaloCliente, nomUsuarioCliente, mailUsuarioCliente, telUsuarioCliente, tipoTarjetaCliente, registroCliente, cumpleCliente, tipoRegistro
    }
}

class ViewController: UIViewController {
    @IBOutlet weak var btnFB: UIButton!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        //self.btnPreguntar.layer.cornerRadius = 5
        self.btnFB.layer.cornerRadius = 5
        
        if (FBSDKAccessToken.current() != nil){
            print("Logueado")
            camposUsuario()
        }else{
            print("Sin loguearse")
        }
        // Do any additional setup after loading the view, typically from a nib.
    }
    
    //Botón para iniciar sesión
    @IBAction func fbloginBtn(_ sender: UIButton) {
        loginFB()
    }
    
    
    //Función para disque poner la barra de estado con letras blancas
    override var preferredStatusBarStyle: UIStatusBarStyle {
        return .lightContent
    }
    
    
    //Función para iniciar sesión con Facebook
    func loginFB(){
        
        FBSDKLoginManager().logIn(withReadPermissions: ["email", "public_profile"], from: nil) {
            (result, error) in
            if let error = error {
                print(error.localizedDescription)
                return
            }
            guard let result = result else {return}
            if result.isCancelled{
                return
            }else{
                self.camposUsuario()
            }
        }
        
    }
    
    func camposUsuario(){
        
        FBSDKGraphRequest(graphPath: "me", parameters: ["fields": "first_name, last_name, birthday, email, picture.type(large)"]).start {(conexion, result, error) in
            if let error = error {
                print(error.localizedDescription)
            }
            if let fields = result as? [String:Any]{
                
                let nombreCliente = fields["first_name"] as? String ?? ""
                let apellidoCliente = fields["last_name"] as? String ?? ""
                let mailCliente = fields["email"] as? String ?? ""
                
                let myURL = NSURL(string: "http://localhost:8888/GentsMovil/controller/registroFB.php")
                let request = NSMutableURLRequest(url:myURL! as URL)
                request.httpMethod = "POST"
                
                let postString = "mail=\(mailCliente)"
                request.httpBody = postString.data(using: String.Encoding.utf8)
                URLSession.shared.dataTask(with: request as URLRequest, completionHandler:{ (data, response, error) in
                DispatchQueue.main.async {
                    
                    if let e = error {
                        self.displayAlertMessage(userMessage: e.localizedDescription)
                        return
                    }
                            do{
                                let response = try? JSONDecoder().decode(Response.self, from: data!)
                                if let firstResult = response?.result.first {
                                    UserDefaults.standard.set(firstResult.nombreCliente, forKey: "nombreCliente")
                                }
                                if response?.status == "400" {
                                    
                                    let vistaInicio = (self.storyboard?.instantiateViewController(withIdentifier: "vistaInicio") as? UINavigationController)
                                    
                                    let appDelegate = UIApplication.shared.delegate
                                    
                                    appDelegate?.window??.rootViewController = vistaInicio
                                    
                                    //Abre la ventana de registro si no existe una cuenta de correo ya existente en el servidor
                                    
                                } else if response?.status == "404"{
                                    //Se descargan los datos desde Facebook
                                    UserDefaults.standard.set(fields["first_name"], forKey: "first_name")
                                    UserDefaults.standard.set(fields["last_name"], forKey: "last_name")
                                    UserDefaults.standard.set(fields["email"], forKey: "email")
                                    UserDefaults.standard.set(fields["picture"], forKey: "picture")
                                    UserDefaults.standard.set(fields["birthday"], forKey: "birthday")
                                    UserDefaults.standard.synchronize()
                                    
                                    let Perfil = (self.storyboard?.instantiateViewController(withIdentifier: "verificaPerfil") as? UINavigationController)
                                    let appDelegate = UIApplication.shared.delegate
                                    appDelegate?.window??.rootViewController = Perfil
                                }
                            }catch{
                                print(error)
                            }
                        }
            }).resume()
            }
        }
    }
    func displayAlertMessage(userMessage:String){
        
        let myAlert = UIAlertController(title: "Atención", message: userMessage, preferredStyle: UIAlertController.Style.alert);
        let okAction =  UIAlertAction(title: "Ok", style: UIAlertAction.Style.default, handler: nil)
        myAlert.addAction(okAction);
        self.present(myAlert, animated: true, completion:nil)
        
    }
    override func viewDidAppear(_ animated: Bool) {
        super.viewDidAppear(animated)
        
        if (UserDefaults.standard.object(forKey: "tuto") != nil){
            return
        }else{
            if let inicioVC = storyboard?.instantiateViewController(withIdentifier: "tutorial") as? PaginacionViewController{
                self.present(inicioVC, animated: true, completion: nil)
            }
        }
    }
}

I would appreciate your help, greetings.

#2

hi @rockyto,
when you create your struct, you are set the type of data you are expecting from your JSON, so when you know that some of the data could return as null, then you cannot declare them as Int or String, you have to declare them as Int? and String? instead,

cheers,

#3

So I do not declare the kind of variables I expect?
Greetings, thanks for commenting

#4

Hi @rockyto,
Look up optionals, the answer to your problem here is Optionals.

If you declare numeroTarjeta as String then Swift expects you to return a String value, if you get a value that is not string or null, then it will not work and fail. So if you know that some of these properties will return null, then set them as optionals using the ? at the end of the declaration.

This has been the same with many other JSON parsing libraries earlier.

cheers,