In swift, how can I wait until a server response is received before I proceed?

后端 未结 1 1446
独厮守ぢ
独厮守ぢ 2021-01-17 06:10

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?

相关标签:
1条回答
  • 2021-01-17 06:44

    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:

    1. 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:

    2. Give that segue a storyboard identifier by selecting the segue and going to the "Attributes Inspector" tab:

    3. Hook up the button (or whatever is going to trigger this segue) to an @IBAction.

    4. 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
      }
      
    0 讨论(0)
提交回复
热议问题