Swift 4中shouldPerformSegue异步验证返回值异常问题求助
问题原因分析
你的问题核心在于异步操作和同步方法的冲突:
shouldPerformSegue(withIdentifier:sender:)是一个同步方法,它要求立即返回布尔值来决定是否执行跳转。但你在方法内部发起的URLSession.shared.dataTask(with:)是异步网络请求——这个请求会在后台线程执行,不会阻塞当前主线程,所以方法会直接跳过请求代码,走到最后的return decision语句,此时decision还是你初始化的true,网络请求甚至还没拿到服务器的响应,自然无法修改这个变量的值。
简单说:你的return语句跑得比网络请求快,等请求结果回来的时候,这个方法早就执行完了,修改decision已经没用了。
正确的解决方案
不能在shouldPerformSegue里做异步验证,正确的思路是:
- 先禁用登录按钮直接触发segue的逻辑(把segue的触发方式从按钮点击改成手动触发)
- 在登录按钮的点击事件里发起异步验证请求
- 等服务器返回结果后,再手动决定是否执行segue跳转
下面是修改后的代码示例:
// 登录按钮的点击事件 @IBAction func loginButtonTapped(_ sender: UIButton) { // 先检查输入是否为空,避免空值崩溃 guard let userNameText = userName.text?.lowercased(), !userNameText.isEmpty, let passWordText = passWord.text?.lowercased(), !passWordText.isEmpty else { // 这里可以弹框提示用户输入账号密码 print("请输入账号和密码") return } // 构建网络请求 let url = URL(string:"http://192.23.25.98/login/php")! var request = URLRequest(url: url) request.httpMethod = "POST" let body = "UserNameLogIn=\(userNameText)&PasswordLogIn=\(passWordText)" request.httpBody = body.data(using: .utf8) // 发起异步网络请求 URLSession.shared.dataTask(with: request) { [weak self] data, response, error in // 用weak self避免循环引用,防止内存泄漏 guard let self = self else { return } // 回到主线程处理UI和跳转逻辑(iOS要求UI操作必须在主线程) DispatchQueue.main.async { if let error = error { print("网络请求出错: \(error)") // 弹框提示用户网络问题 return } guard let responseData = data else { print("服务器未返回数据") // 弹框提示错误 return } do { // 解析JSON数据 guard let json = try JSONSerialization.jsonObject(with: responseData, options: []) as? [AnyHashable: Any] else { print("JSON解析失败") // 弹框提示错误 return } // 根据服务器返回结果判断是否允许跳转 let status = json["status"] let shouldLoginSuccess = status != nil && json.count > 3 if shouldLoginSuccess { // 验证通过,手动执行segue self.performSegue(withIdentifier: "你的Segue标识符", sender: self) } else { // 验证失败,提示用户账号或密码错误 print("登录失败,请检查账号密码") } } catch { print("解析数据出错: \(error)") // 弹框提示错误 } } }.resume() } // 如果不需要额外的同步判断,可以删除这个方法;如果有其他同步逻辑(比如检查表单),可以保留 override func shouldPerformSegue(withIdentifier identifier: String, sender: Any?) -> Bool { // 这里可以添加其他同步验证逻辑,比如是否勾选了隐私协议等 return true }
额外注意事项
- 记得把代码中的
"你的Segue标识符"替换成你项目中实际的segue ID - 所有UI相关操作(比如弹框提示)必须放在
DispatchQueue.main.async里执行,否则会导致崩溃或UI异常 - 要处理各种异常情况(网络错误、数据为空、解析失败等),给用户清晰的错误提示,提升体验
内容的提问来源于stack exchange,提问作者Ahmed
相关产品推荐
相关产品推荐

