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

别等时光非礼了梦想. 提交于 2019-12-01 14:51:16

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
    }
    
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!