I would like to only execute a segue if I get a certain response from the server. In swift, how can I wait until I get a response to continue?
-
7use completionHandler: – Khundragpan Jul 27 '16 at 15:54
-
http://stackoverflow.com/questions/8427836/how-to-make-program-wait-for-asynchronous-nsurlconnection-to-finish-before-proce – Amit Jagesha シ Jul 27 '16 at 15:56
-
1you do almost never want to actively *wait* since that blocks your current thread. – luk2302 Jul 27 '16 at 16:31
1 Answers
Bottom line, you don't "wait" for the response, but rather simply specify what you want to happen when the response comes in. For example, if you want to perform a segue when some network request is done, you should employ the completion handler pattern.
The issue here is that you're probably accustomed to just hooking your UI control to a segue in Interface Builder. In our case, we don't want to do that, but rather we want to perform the network request, and then have its completion handler invoke the segue programmatically. So, we have to create a segue that can be performed programmatically and then hook your button up to an @IBAction
that performs the network request and, if appropriate, performs the segue programmatically. But, note, there should be no segue hooked up to the button directly. We'll do that programmatically.
For example:
Define the segue to be between the two view controllers by control-dragging from the view controller icon in the bar above the first scene to the second scene:
Give that segue a storyboard identifier by selecting the segue and going to the "Attributes Inspector" tab:
Hook up the button (or whatever is going to trigger this segue) to an
@IBAction
.Write an
@IBAction
that performs network request and, upon completion, programmatically invokes that segue:@IBAction func didTapButton(_ sender: Any) { let request = URLRequest(...). // prepare request however your app requires let waitingView = showWaitingView() // present something so that the user knows some network request is in progress // perform network request let task = URLSession.shared.dataTask(with: request) { data, response, error in // regardless of how we exit this, now that request is done, let's // make sure to remove visual indication that network request was underway defer { DispatchQueue.main.async { waitingView.removeFromSuperview() } } // make sure there wasn't an error; you'll undoubtedly have additional // criteria to apply here, but this is a start guard let data = data, error == nil else { print(error ?? "Unknown error") return } // parse and process the response however is appropriate in your case, e.g., if JSON: // // guard let responseObject = try? JSONSerialization.jsonObject(with data) else { // // handle parsing error here // return // } // // // do whatever you want with the parsed JSON here // do something with response DispatchQueue.main.async { performSegue(withIdentifier: "SegueToSceneTwo", sender: self) } } task.resume() } /// Show some view so user knows network request is underway /// /// You can do whatever you want here, but I'll blur the view and add `UIActivityIndicatorView`. private func showWaitingView() -> UIView { let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .Dark)) effectView.translatesAutoresizingMaskIntoConstraints = false view.addSubview(effectView) NSLayoutConstraint.activateConstraints([ effectView.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor), effectView.trailingAnchor.constraintEqualToAnchor(view.trailingAnchor), effectView.topAnchor.constraintEqualToAnchor(view.topAnchor), effectView.bottomAnchor.constraintEqualToAnchor(view.bottomAnchor) ]) let spinner = UIActivityIndicatorView(activityIndicatorStyle: .WhiteLarge) effectView.addSubview(spinner) spinner.translatesAutoresizingMaskIntoConstraints = false NSLayoutConstraint.activateConstraints([ spinner.centerXAnchor.constraintEqualToAnchor(view.centerXAnchor), spinner.centerYAnchor.constraintEqualToAnchor(view.centerYAnchor) ]) spinner.startAnimating() return effectView }

- 415,655
- 72
- 787
- 1,044
-
The screenshots and code are good but they don't seem to have anything to do with using `NSURLSession`. – Tom Harrington Jul 27 '16 at 18:50
-
@TomHarrington Step 4 is the performing of the `NSURLSessionTask`. Steps 1-3 outline the things you need to do to perform the segue programmatically that we do in step 4. If I understand the question correctly, the OP was asking how to wait for network response before performing segue. – Rob Jul 27 '16 at 18:54
-
OK, I guess I got lost in all the talk about how to set up a segue. – Tom Harrington Jul 27 '16 at 18:55
-
@TomHarrington - Yeah, I didn't explain that clearly enough. It's just that when people talk about having segue wait for some network request, it's usually a two part problem, that they're unfamiliar with asynchronous patterns, but also that they're not accustomed to performing segues programmatically. I've tried to add some text to clarify my point. – Rob Jul 27 '16 at 19:17