You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Swift项目求助:shouldPerformSegue中doApi()执行顺序异常

问题根源

你遇到的是典型的异步代码执行顺序问题——URLSession.dataTask是异步执行的网络请求,当你在shouldPerformSegue里调用doApi()时,方法会立刻启动请求,然后直接返回初始的check = false,而请求完成后设置check = true的逻辑要等到网络请求结束才会运行,这就导致你的打印语句先于API回调执行。

而且shouldPerformSegue是系统要求同步返回结果的方法,没法在这里等待异步操作完成,所以得换个思路处理。

解决方案

我们可以把Segue改成手动触发,步骤如下:

1. 先修改Storyboard设置

  • 删掉登录按钮和目标控制器之间的自动触发Segue(或者把Segue的触发方式从按钮点击改为手动)
  • 保留Segue的identifier为performSegueLogin不变

2. 修改代码逻辑

把API请求放到doLogin方法里,等异步请求完成后,再手动决定是否执行Segue:

class ViewController: UIViewController {
    var loginArr = [String]()
    @IBOutlet weak var _output: UILabel!
    @IBOutlet weak var _username: UITextField!
    @IBOutlet weak var _password: UITextField!
    
    @IBAction func doLogin(_ sender: Any) {
        loginArr.removeAll()
        guard let username = _username.text, !username.isEmpty,
              let password = _password.text, !password.isEmpty else {
            // 提示用户输入不能为空
            _output.text = "用户名或密码不能为空"
            return
        }
        loginArr.append(username)
        loginArr.append(password)
        self._output.text = username
        
        // 调用API验证登录
        doApi { [weak self] isSuccess in
            guard let self = self else { return }
            if isSuccess {
                print("2 - true")
                // 验证通过,手动执行Segue
                self.performSegue(withIdentifier: "performSegueLogin", sender: self)
            } else {
                print("1 - false")
                // 验证失败,更新UI提示用户
                self._output.text = "登录失败,请检查账号密码"
            }
        }
    }
    
    // 修改doApi为带回调的异步方法,不再直接返回Bool
    func doApi(completion: @escaping (Bool) -> Void){
        let headers = [
            "cache-control": "no-cache",
            "postman-token": "6f8a-12c6-87a1-ac0f25d6385a"
        ]
        guard let username = _username.text,
              let password = _password.text,
              let url = URL(string: "https://projects2018.sz-ybbs.ac.at/~szmed/indyapp/indyapi.php?func=0&user=\(username)&pass=\(password)") else {
            completion(false)
            return
        }
        
        var request = URLRequest(url: url, cachePolicy: .useProtocolCachePolicy, timeoutInterval: 10.0)
        request.httpMethod = "GET"
        request.allHTTPHeaderFields = headers
        
        let session = URLSession.shared
        let dataTask = session.dataTask(with: request) { (data, response, error) -> Void in
            var loginSuccess = false
            defer {
                // 回到主线程执行回调(UI操作必须在主线程)
                DispatchQueue.main.async {
                    completion(loginSuccess)
                }
            }
            
            if let error = error {
                print("网络请求出错:\(error.localizedDescription)")
                return
            }
            
            guard let data = data else {
                print("未获取到返回数据")
                return
            }
            
            do {
                if let json = try JSONSerialization.jsonObject(with: data, options: []) as? [String:Any] {
                    print(json)
                    // 这里建议根据API实际返回的状态判断登录是否成功,比如json["success"] == true
                    loginSuccess = true
                }
            } catch {
                print("JSON解析失败:\(error.localizedDescription)")
            }
        }.resume()
    }
    
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "performSegueLogin" {
            let DashboardC = segue.destination as! DashboardController
            DashboardC.receivedStringArr = loginArr
        }
    }
    
    // 不再需要shouldPerformSegue,因为我们手动控制Segue触发时机
}

关键改动说明

  • 将doApi改成带completion回调的异步方法,确保能在网络请求完成后通知调用方结果
  • 在doLogin中调用doApi,根据回调结果手动触发Segue或提示错误
  • 添加guard语句处理空值,避免强制解包导致崩溃
  • 网络请求回调中用DispatchQueue.main.async切回主线程,保证UI操作的安全性
  • 移除shouldPerformSegue方法,改为手动控制Segue触发
额外建议
  • 不要依赖强制解包(比如_username.text!),用guard或if let处理空值,提升代码稳定性
  • 登录成功的判断要结合API实际返回的字段,比如API返回"status": "success"才判定为登录成功,而不是仅判断请求是否成功
  • 可以添加加载动画(比如UIActivityIndicatorView),让用户感知到登录请求正在进行

内容的提问来源于stack exchange,提问作者Pheeerox

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.14 09:01:28