1

I have a JSON Post authentication to make a login request, of course I need to send the user & password parameters to receive a response for filling my HomeViewController, so I need first to validate the two parameters, and if the user doesn't exist of course I'm going to send an Alert and forbid the access to the Home. The thing is that I don't know in which method do I have to put this validation, because the way I'm doing it throws me an alert before the validation. This is my code:

class LoginViewController: UIViewController, LoginProtocol {

    @IBOutlet weak var username: UITextField!
    @IBOutlet weak var password: UITextField!
    @IBOutlet weak var activityIndicator: UIActivityIndicatorView!

    var user : String = ""
    var psw : String = ""
    var idResponse : String = ""
    var message : String = ""
    override func viewDidLoad() {
        super.viewDidLoad()
    }

    @IBAction func validateLogin(_ sender: Any) {
        DoLogin(self.username.text!, self.password.text!)
    }

    @IBAction func login(_ sender: Any) {

        if self.idResponse != "0" {
            validation(message: self.message)
        } else {
            let vc = self.storyboard!.instantiateViewController(withIdentifier: "home") as! HomeViewController
            self.present(vc, animated: false, completion: nil)
            vc.getUser = self.username.text!
            vc.getPassword = self.password.text!
        }
    }

    func validation(message: String) {
        let myAlert = UIAlertController(title: "Alert", message: message, preferredStyle: UIAlertControllerStyle.alert)
        let okAction = UIAlertAction (title: "Ok", style: UIAlertActionStyle.default, handler: nil)
        myAlert.addAction(okAction)
        self.present(myAlert, animated: true, completion: nil)
        return
    }

func DoLogin(_ user:String, _ psw:String)
    {
        let url = URL(string: "http://162.209.99.39:8080/MiClaroBackend/auth")
        let session = URLSession.shared

        let request = NSMutableURLRequest(url: url!)
        request.httpMethod = "POST"

        self.username.text = user
        self.password.text = psw

        let paramToSend = ["username":user,"password":psw]
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = try! JSONSerialization.data(withJSONObject: paramToSend)

        let task = session.dataTask(with: request as URLRequest, completionHandler: {
            (data, response, error) in

            guard let _:Data = data else
            {
                return
            }

            let json:AnyObject?

            do {
                json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
                if let parseJSON = json{
                    let loginModel = LoginModel()

                    let defaultServiceResponse = parseJSON["defaultServiceResponse"] as! NSDictionary
                    loginModel.message = defaultServiceResponse["message"] as! String
                    loginModel.idResponse = defaultServiceResponse["idResponse"] as! Int

                    self.idResponse = String(loginModel.idResponse)
                    self.message = loginModel.message

                    print(json!)

                }
            } catch {
                let error = ErrorModel()
                error.phrase = "PARSER_ERROR"
                error.code = -1
                error.desc = "Parser error in login action"
            }
        })

        task.resume()
    }

The validateLogin method is attached to a TextView with the action: "EditingDidEnd". So what I need is that when I finish writing the password, the DoLogin function validates that exists and let me continue to the HomeViewController, but the issue is that when I click the button 'Ingresar'(Login), it shows a blank Alert first and only the second time I click the button it let me through immediately. I don't know why is sending the Alert that I declare at the "func validation" if I'm not calling it before. I'm going to attach a picture to show you the Alert that is appearing:

The Alert

mfaani
  • 33,269
  • 19
  • 164
  • 293
  • 3
    Are you aware that `dataTask(with` works asynchronously? – vadian Jul 13 '17 at 15:14
  • when you want validate? and after validate you want to call login? – BHAVIK Jul 13 '17 at 15:16
  • what is the Validate Login And Login Button ? After enter username And password which funvtion called?? – BHAVIK Jul 13 '17 at 15:18
  • 1
    Not related to what you want to know but FYI: this line `DoLogin(self.username.text!, self.password.text!)` would crash if the user hasn't entered either password or username. So it's best to unwrap safely. See [here](https://stackoverflow.com/questions/25828301/how-is-swift-if-let-evaluated/38041086#38041086) – mfaani Jul 13 '17 at 15:23
  • Thank you very much for your advises, that really helped. And I want to validate after I finish writing the password, but to validate the parameters I need to call the func DoLogin because the users are stored at the server. So, after the validation I have to call the func Login (that is attached to the button 'Ingresar') to pass through the HomeViewController, but when I click the button is when the alert is shown, and I don't know why that alert is appearing, it shouldn't be that way. – Zita Noriega Estrada Jul 13 '17 at 15:42
  • @vadian I believe that is my mistake, I was not considering that dataTask(with works asynchronously, so, do you have a suggestion for me to make the validation correct? – Zita Noriega Estrada Jul 13 '17 at 16:06
  • 1
    You have to implement a completion handler to get notified. There are hundreds of related questions here on SO. – vadian Jul 13 '17 at 16:09
  • @vadian Sorry for asking a lot but I couldn't find a question with the correct answer I need, can you show an example of a question like this, with the completion handler you said? – Zita Noriega Estrada Jul 13 '17 at 16:23
  • 1
    Short example: https://stackoverflow.com/questions/44131678/completion-handler-swift-3-return-a-variable-from-function/44131927#44131927 – vadian Jul 13 '17 at 16:27
  • Thank you very much, you helped me a lot, you're wonderful!!! :D – Zita Noriega Estrada Jul 13 '17 at 16:31

3 Answers3

1

Chances are your EditingDidEnd method calls DoLogin which is processing in background when you press the Login button. hence your if condition below becomes true as your idResponse is initialized to "" empty string.

if self.idResponse != "0"

Rectify this if condition to check if its empty then dont call the validation message.

The best way to do this is to call your DoLogin only after click of the Login button and if in case you have success redirect to Home page. Otherwise show the alert. Please note do the UI action on the main thread.

Kapil G
  • 4,081
  • 2
  • 20
  • 32
  • Can you please help me showing me how the if conditional has to be? Because I'm writing it like this and nothing happens: if self.idResponse .isEmpty == true { } else if self.idResponse != "0" { validation(message: self.message) } else { let vc = self.storyboard!.instantiateViewController(withIdentifier: "home") as! HomeViewController self.present(vc, animated: false, completion: nil) vc.getUser = self.username.text! vc.getPassword = self.password.text! } – Zita Noriega Estrada Jul 13 '17 at 15:58
  • 1
    As you would have go from Vadian's answer, once you add this showing of alert code in the completion handler, you would not face the response empty issue so you will not see an empty Alert. In your completion handler you can have the valid response condition as well as invalid response condition and perform your action accordingly. The success and error condition will depend on the response that your validation service will return. – Kapil G Jul 13 '17 at 17:38
1

First Update the Code And User Like this

func DoLogin(_ user:String, _ psw:String)
    {
        let url = URL(string: "http://162.209.99.39:8080/MiClaroBackend/auth")
        let session = URLSession.shared

        let request = NSMutableURLRequest(url: url!)
        request.httpMethod = "POST"


        let paramToSend = ["username":user,"password":psw]
        request.setValue("application/json", forHTTPHeaderField: "Content-Type")
        request.httpBody = try! JSONSerialization.data(withJSONObject: paramToSend)

        let task = session.dataTask(with: request as URLRequest, completionHandler: {
            (data, response, error) in

            guard let _:Data = data else
            {
                return
            }

            let json:AnyObject?

            do {
                json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
                if let parseJSON = json{
                    let loginModel = LoginModel()

                    let defaultServiceResponse = parseJSON["defaultServiceResponse"] as! NSDictionary
                    loginModel.message = defaultServiceResponse["message"] as! String
                    loginModel.idResponse = defaultServiceResponse["idResponse"] as! Int

                    self.idResponse = String(loginModel.idResponse)
                    self.message = loginModel.message
 if self.idResponse != "0" {
            validation(message: self.message)
        } else {
  let vc = self.storyboard!.instantiateViewController(withIdentifier: "home") as! HomeViewController
            self.present(vc, animated: false, completion: nil)
            vc.getUser = user!
            vc.getPassword = psw!
        }

                }
            } catch {
                let error = ErrorModel()
                error.phrase = "PARSER_ERROR"
                error.code = -1
                error.desc = "Parser error in login action"
            }
        })

        task.resume()
    }
BHAVIK
  • 890
  • 7
  • 35
  • Sorry but that doesn't work because to make the validation is needed first to write the user and password on the TextView, so I can't put the conditional at the JSON serialization. – Zita Noriega Estrada Jul 13 '17 at 15:57
0

If You want to add alert in imageview use this code

var imageView = UIImageView(frame: CGRectMake(220, 10, 40, 40))
imageView.image = yourImage

alert.view.addSubview(imageView)
BHAVIK
  • 890
  • 7
  • 35