0
votes

I'm new to iOS and was hoping someone would be willing to help me out with an issue I'm having

Say I have 2 Views in my storyboard: - View1: Has 1 text box - View2: Has 1 Label

Each being respectively controlled by a ViewControllers: - FirstViewController - SecondViewController

My app would send the text of the textbox in View1 as an HTTP (POST) request to an API, and would display on View2 the result which is sent back in JSON format.

My approach is to use the prepare(for segue:,Sender:), however I am having a hard time returning the JSON response from Task() in order to send it to SecondViewController via a Segue.

class ResultViewController: UIViewController {


@IBOutlet var text_input: UITextField!

Let api_url = (the api url)

func makeRequest(voucher_number:String, redemption_code:String){

    let json: [String: Any] = [
        "input" : text_input.text
        ]

    let request_json = try? JSONSerialization.data(withJSONObject: json)


    let url:URL = URL(string: api_url)!
    let session = URLSession.shared

    var request = URLRequest(url: url)
    request.httpMethod = "POST"
    request.cachePolicy = NSURLRequest.CachePolicy.reloadIgnoringCacheData

    request.httpBody = request_json

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

        guard let _:Data = data, let _:URLResponse = response  , error == nil else {
            return
        }

        let json: Any?

        do
        {
            json = try JSONSerialization.jsonObject(with: data!, options: [])
        }
        catch
        {
        }

        guard let server_response = json as? [String: Any] else
        {
            return
        }

          //This is where I think the return should take place 
          //but can't figure out how

        })

    task.resume()
}

}

I know I would need to modify my func declaration by adding the return syntax, but I can't figure out how to return data in the first place :P so I skipped this part for the time being.

I would then do the following to send the response to SecondViewController

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "firstSegue" {
        if let resultViewController = segue.destination as? SecondViewController {

            if (text_input.text != nil && redemption_code.text != nil) {
               if let json_response = makeRequest() {
            SecondViewController.request_result = json_response
                }
                  // request_result is the variable in 
                  // SecondViewController that will store the data 
                  // being passed via the segue.
            }
        }
    }
}

I know my code may not be the best practice for what I'm trying to achieve. And I'm open to suggestions to tackle a different approach, as long as it's not too advanced for me.

Cheers

1
No need to use segue in this case. Just present/push your new viewController in the call back method of the task.jokeman

1 Answers

0
votes

Notifications are a good way to forward JSON data out of completion handler blocks, like:

NotificationCenter.default.post(name: Notification.Name(rawValue:"JSON_RESPONSE_RECEIVED"), object: nil, userInfo: server_response)

Register and handle the notification in FirstViewController:

NotificationCenter.default.addObserver(self, selector: #selector(FirstViewController.json_Response_Received(_:)), name:NSNotification.Name(rawValue: "JSON_RESPONSE_RECEIVED"), object: nil)

(in viewDidLoad()) and:

func json_Response_Received(_ notification:Notification) {

responseDictionary = (notification as NSNotification).userInfo as! [String:AnyObject];

self.performSegue(withIdentifier: "SegueToSecondController", sender: self)

}

Then you can pass responseDictionary to SecondViewController in:

    override func prepare(for segue:UIStoryboardSegue, sender:Any?) {

        if (segue.identifier == "SegueToSecondController") {

          secondViewController = segue.destinationViewController as! SecondViewController
          secondViewController.response = responseDictionary 

        }
    }