Swift中如何等待API请求完成后再执行Segue跳转?
问题
我是Swift新手,目前遇到一个问题:点击按钮时想先从API请求数据,把获取到的数据传递给另一个视图控制器后再执行Segue跳转。但现在点击按钮后,请求刚启动就直接跳转到第二个视图控制器,根本没携带任何数据。
如何等待videoManager.performRequest(with: videoLinkTextField.text!)执行完成后再执行Segue?
当前按钮代码
@IBAction func getVideoButtonPressed(_ sender: UIButton) { if videoLinkTextField.text != nil, videoLinkTextField.text!.contains("tiktok") { videoManager.performRequest(with: videoLinkTextField.text!) DispatchQueue.main.async { self.performSegue(withIdentifier: "GoToVideo", sender: self) } } else { videoLinkTextField.text = "" let alert = UIAlertController(title: "Error", message: "Please enter a valid link", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "Ok", style: .default)) present(alert, animated: true, completion: nil) } }
当前prepare函数
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { if segue.identifier == "GoToVideo" { DispatchQueue.main.async { let destionationVC = segue.destination as! ResultViewController print("Test \(self.videoUrl)") destionationVC.videoUrl = self.videoUrl } } }
当前performRequest函数
func performRequest(with videoUrl: String) { let request = NSMutableURLRequest(url: NSURL(string: "https://tiktok-downloader-download-videos-without-watermark1.p.rapidapi.com/media-info/?link=\(videoUrl)")! as URL, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0) request.httpMethod = "GET" request.allHTTPHeaderFields = headers let session = URLSession.shared let dataTask = session.dataTask(with: request as URLRequest, completionHandler: { data, _, error in if error != nil { self.delegate?.didFailedWithError(error!) } if let safeData = data { if let video = self.parseJSON(safeData) { self.delegate?.didUpdateVideo(self, video: video) } } }) dataTask.resume() }
解决方案
核心问题是performRequest是异步网络请求,你现在是请求刚发出去就立刻执行Segue,这时候数据还没回来。要解决这个,得把Segue的触发时机放在请求完成的回调里。
步骤1:移除按钮里的Segue调用
修改按钮点击方法,删掉直接调用performSegue的代码,只保留请求触发:
@IBAction func getVideoButtonPressed(_ sender: UIButton) { guard let link = videoLinkTextField.text, link.contains("tiktok") else { videoLinkTextField.text = "" let alert = UIAlertController(title: "错误", message: "请输入有效的链接", preferredStyle: .alert) alert.addAction(UIAlertAction(title: "确定", style: .default)) present(alert, animated: true) return } // 只触发请求,不立即跳转 videoManager.performRequest(with: link) }
步骤2:在代理回调里触发Segue
你的videoManager用了代理模式,在didUpdateVideo回调(数据请求成功并解析完成时触发)里调用Segue:
假设当前视图控制器已遵守VideoManagerDelegate,实现以下方法:
extension YourViewController: VideoManagerDelegate { func didUpdateVideo(_ manager: VideoManager, video: Video) { // 把解析后的视频数据赋值给当前控制器的videoUrl self.videoUrl = video.url // 根据你的Video模型实际字段调整 // 回到主线程触发Segue(网络回调在后台线程,UI操作必须在主线程) DispatchQueue.main.async { self.performSegue(withIdentifier: "GoToVideo", sender: self) } } func didFailedWithError(_ error: Error) { // 请求失败时弹提示 DispatchQueue.main.async { let alert = UIAlertController(title: "请求失败", message: error.localizedDescription, preferredStyle: .alert) alert.addAction(UIAlertAction(title: "确定", style: .default)) self.present(alert, animated: true) } } }
步骤3:优化prepare函数
prepare方法本身就在主线程执行,不需要再套DispatchQueue.main.async,直接赋值即可:
override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard segue.identifier == "GoToVideo", let destinationVC = segue.destination as? ResultViewController else { return } // 此时videoUrl已经有值了,直接传递 destinationVC.videoUrl = self.videoUrl print("传递的视频链接:\(self.videoUrl ?? "无数据")") }
额外建议
- 避免强制解包(
!),尽量用guard let或if let处理可选值,减少崩溃风险 - 网络请求的URL最好做百分号编码,避免链接里有特殊字符导致请求失败:
if let encodedUrl = videoUrl.addingPercentEncoding(withAllowedCharacters: .urlQueryAllowed), let requestUrl = URL(string: "https://tiktok-downloader-download-videos-without-watermark1.p.rapidapi.com/media-info/?link=\(encodedUrl)") { // 使用requestUrl创建请求 }
内容的提问来源于stack exchange,提问作者themmfa
相关产品推荐
相关产品推荐

