Reginald Reginald - 2 months ago 10
reST (reStructuredText) Question

swiftyJSON parsing using REST API - not populating the model

Well, I am beginner at swift and more on Java programmer and got problem when parsing JSON coming from the REST API. I am using an MVC pattern so after I pressed the login button what I want to do is populate the user model with the JSON data I've received from the API but what happening is the data I've received in the request method aren't populating the variables I've created in the User.swift.

Model.swift:

class Model{

var user = User()
var id = 0

func getAuthentication(username: String, password: String){

let baseURL = "http://urag.co/bci_api/api/auth"
let url = NSURL(string: baseURL)!
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.HTTPBody = "{\n \"username\": \"\(username)\",\n \"password\": \"\(password)\"\n}".dataUsingEncoding(NSUTF8StringEncoding);

let session = NSURLSession(configuration: NSURLSessionConfiguration.defaultSessionConfiguration())
let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in

if error == nil{
let swiftyJSON = JSON(data: data!)
self.user.ID = swiftyJSON["id"].intValue
print(self.user.ID)

} else {
print("There was an error")
}
}
task.resume()
}
}


User.swift:

class User {

var ID = 0
var userName = ""
var token = ""
}


What I wanted to do here is to populate the ID of user coming from the Model class
getAuthentication()
method/

LoginViewController:

class LoginViewController: UIViewController{

@IBOutlet weak var userName: UITextField!
@IBOutlet weak var password: UITextField!
@IBOutlet weak var loginButton: UIButton!

var user = User()
var model = Model()
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
loginButton.layer.borderWidth = 2
loginButton.layer.borderColor = UIColor.whiteColor().CGColor
loginButton.layer.cornerRadius = 5.0

//this is to create gesture to tapAround and dismiss the keyboard when tap around the screen
let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(LoginViewController.dismissKeyboard))
view.addGestureRecognizer(tap)

}

//an Obj-C function that will be called to dismiss the keyboard when tap around
@objc private func dismissKeyboard(){
view.endEditing(true)
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}



@IBAction func login(sender: UIButton) {
if let userName = self.userName.text{
if let password = self.password.text{
model.getAuthentication(userName, password: password)
print(user.ID)
if user.ID != 0 {
switch(user.ID){
case 1: performSegueWithIdentifier("loginAdmin", sender: nil)
case 2: performSegueWithIdentifier("loginPatient", sender: nil)
case 3: performSegueWithIdentifier("loginDoctor", sender: nil)
default:
break
}
}
}
}
}
@IBAction func unwindFromForgotPassword(segue: UIStoryboardSegue) {
}

}


What is happening now is after i press the login button the
print(user.ID)
from the
LoginViewController
returns
0
and then the
print(self.user.ID)
returns
3
meaning it received and parsed the value from the API but i'm not sure why is it that the
print(user.ID)
returns
0
while inside the
getAuthentication()
method it returns
3
.

Answer

I've solved my problem using the semaphores, I am not sure if this is the best way but it solved it for now. Still hoping to find some better idea but the error I was facing was that it wasn't waiting for the json data downloaded in the api to be finished.

Model.swift

class Model {

   var id = 0
   var token = ""

   func getAuthentication(username: String, password: String){
     let semaphore = dispatch_semaphore_create(0);
     let baseURL = "http://urag.co/bci_api/api/auth"
     let url = NSURL(string: baseURL)!
     let request = NSMutableURLRequest(URL: url)
     request.HTTPMethod = "POST"
     request.HTTPBody = "{\n  \"username\": \"\(username)\",\n  \"password\": \"\(password)\"\n}".dataUsingEncoding(NSUTF8StringEncoding);

     let session = NSURLSession.sharedSession()
     let task = session.dataTaskWithRequest(request) { (data, response, error) -> Void in

        if error == nil{
            let swiftyJSON = JSON(data: data!)
            self.id = swiftyJSON["id"].intValue
            self.token = swiftyJSON["meta"]["token"].stringValue
        } else {
            print("There was an error")
        }
      dispatch_semaphore_signal(semaphore);
    }
    task.resume()
    dispatch_semaphore_wait(semaphore, DISPATCH_TIME_FOREVER);
}

LoginViewController.swift

class LoginViewController: UIViewController{

   @IBOutlet weak var userName: UITextField!
   @IBOutlet weak var password: UITextField!
   @IBOutlet weak var loginButton: UIButton!

   var model = Model()
   override func viewDidLoad() {
      super.viewDidLoad()

      loginButton.layer.borderWidth = 2
      loginButton.layer.borderColor = UIColor.whiteColor().CGColor
      loginButton.layer.cornerRadius = 5.0

      //this is to create gesture to tapAround and dismiss the keyboard when tap around the screen
      let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(LoginViewController.dismissKeyboard))
      view.addGestureRecognizer(tap)

  }

  //an Obj-C function that will be called to dismiss the keyboard when tap around
  @objc private func dismissKeyboard(){
     view.endEditing(true)
  }

  override func didReceiveMemoryWarning() {
     super.didReceiveMemoryWarning()
     // Dispose of any resources that can be recreated.
  }



  @IBAction func login(sender: UIButton) {
    if let userName = self.userName.text{
        if let password = self.password.text{
            model.getAuthentication(userName, password: password)
            if model.id != 0 {
                switch(model.id){
                    case 1: performSegueWithIdentifier("loginPatient", sender: nil)
                    case 2: performSegueWithIdentifier("loginPatient", sender: nil)
                    case 3: performSegueWithIdentifier("loginDoctor", sender: nil)
                    default:
                    break
                  }
              }
          }
      }
   }
   @IBAction func unwindFromForgotPassword(segue: UIStoryboardSegue) {
   }

}

And i've also removed the User.swift class because it wasn't really mutated after the function getAuthentication(). So I am still looking for an answer if semaphore will do or what is the best practice for this? Thanks!