0

Here is my code in UploadModel.swift

func uploadSpecialistWithId(login: String, password: String) {
        let requestUrl = URL(string: "http://localhost:3000/api/register/specialist")!
        var request = URLRequest(url: requestUrl)
        request.httpMethod = "POST"
        let postParams = "login=\(login)&password=\(password)"
        print(postParams)
        request.httpBody = postParams.data(using: String.Encoding.utf8)
        let task = URLSession.shared.dataTask(with: request) {(data, response, error)
            in
            if(error != nil) {
                print("error -> \(error!.localizedDescription)")
            } else {
                print("data uploaded")
                self.parseJSONSpecialistResponse(data: data!)
            }

        }
        task.resume()
    }

    func parseJSONSpecialistResponse(data: Data) {

        var jsonResult = NSDictionary()
        let specialist = Specialist()
        do {
            jsonResult = try JSONSerialization.jsonObject(with: data, options: .allowFragments) as! NSDictionary
        } catch let error as NSError {
            print("error -> \(error.localizedDescription)")
        }

        let items = NSMutableArray()

        if let login = jsonResult["login"] as? String,
            let specialistId = jsonResult["_id"] as? String {
            specialist.login = login
            specialist.specialistId = specialistId
            print("Added \(specialist.itemDescribtion())")
            items.add(specialist)
        } else {
            let errorCode = jsonResult["code"] as! Int
            print("Erorr with code -> \(errorCode)")
            items.add(errorCode)
        }

        DispatchQueue.main.async(execute: { () -> Void in
            self.delegate.itemsUploaded(items: items)
        })
    }

But when i was trying to reg the specialist with existing login the segue had performed before i handled the server response. What should I change to solve this problem? Here is my code in ViewController.swift

func itemsUploaded(items: NSArray) {
        if let errorCode = items[0] as? Int {
            if errorCode == 11000 {
                warningLabel.text = "This login is already used"
                error = true
            }
        }
        if let specialist = items[0] as? Specialist {
            self.specialistId = specialist.specialistId!
            print("Value after itemsUploaded --> \(self.specialistId)")
        }
    }

    @IBAction func doneButtonTouched(_ sender: Any) {
        uploadModel.uploadSpecialistWithId(login: loginTextField.text!, password: passwordTextField.text!)
        if(error == false) {
            print("Segue perform value -> \(specialistId)")
            performSegue(withIdentifier: "regToRegCompleteSegue", sender: self)
        }
    }

    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let destination = segue.destination as! RegistrationCompleteViewController
        print("Segue prepare value -> \(specialistId)")
        destination.specialistId = self.specialistId
    }

I understand that i have this issue because of asynchronously of dataTask. But why does it not working when the self.delegate is already in the main queue?

EDIT: Adding a completionHandler didn't solve my problem, but Kamran's offer is working.

Alexander
  • 3
  • 4
  • Possible duplicate of [Can Swift return value from an async Void-returning block?](https://stackoverflow.com/questions/28390635/can-swift-return-value-from-an-async-void-returning-block). Your issue is caused by the same thing and the solution to it is the same as well. Make `uploadSpecialistWithId` call a completion handler when the async network request is finished and call `performSegue` from inside the completion handler. – Dávid Pásztor May 13 '18 at 13:24

2 Answers2

0

You should call performSegue inside the itemsUploaded, once it will only be called when the data is ready.

Another way that you could do this is by using @escaping in your function parseJSONSpecialistResponse to know when it is completed. Inside the block of the completion, you can then call performSegue.

  • That's not an answer. There's no closure in the input parameters of any of the functions, so there's nothing to mark as `@escaping`. – Dávid Pásztor May 13 '18 at 13:23
0

You should perform segue when you are done with response by moving the below lines in itemsUploaded as below,

@IBAction func doneButtonTouched(_ sender: Any) {
     uploadModel.uploadSpecialistWithId(login: logiTextField.text!, password: passwordTextField.text!)
 }

func itemsUploaded(items: NSArray) {
      if let errorCode = items[0] as? Int {
          if errorCode == 11000 {
              warningLabel.text = "This login is already used"
              error = true
          }
       }
       if let specialist = items[0] as? Specialist {
           self.specialistId = specialist.specialistId!
           print("Value after itemsUploaded --> \(self.specialistId)")
       }

      if(error == false) {
           print("Segue perform value -> \(specialistId)")
           performSegue(withIdentifier: "regToRegCompleteSegue", sender: self)
      }
}
Kamran
  • 14,987
  • 4
  • 33
  • 51