Swift中ViewController间Segue传值失败致特斯拉API调用报错
解决ViewController间数据传递失败与特斯拉API调用错误问题
看起来你遇到的核心问题有两个:异步网络请求时机错误+变量作用域混乱导致数据传递为空,再加上一些语法和API调用的小问题,最终触发了「数据格式不正确」的错误提示(本质是空的token/车辆信息无法发起有效API请求)。咱们一步步来修复:
1. 核心问题:异步请求与Segue执行时机不匹配
你在Enter方法里,网络请求刚启动就立刻执行了performSegue——但网络请求是异步的,这时候还没拿到accessToken和vehicle,传递给下一个页面的自然是空值。另外,你定义的vehicle、accessToken等变量是类外的空字符串,而请求里拿到的是局部变量,根本没赋值给类属性,prepare方法里传递的一直是空值。
2. 语法与API调用的小问题
ViewController里的chargeOffPeakSwitch方法,if语句缺少大括号,会导致逻辑异常- 当前代码里调用的是
flashLights命令,不是你需要的startCharging - 没有处理API调用的错误情况,很难定位问题
修正后的完整代码
SecondViewController.swift
import UIKit class SecondViewController: UIViewController, UITextFieldDelegate { // 改为类属性,存储请求到的有效数据 private var vehicle: Vehicle? // 假设Vehicle是特斯拉API返回的车辆类型,不要用String private var accessToken: String? private var userEmail: String? private var userPassword: String? // 初始化特斯拉API实例 private let teslaAPI = TeslaAPI() @IBOutlet weak var UserName: UITextField! @IBOutlet weak var Password: UITextField! @IBOutlet weak var TextView: UITextView! override func viewDidLoad() { super.viewDidLoad() UserName.delegate = self Password.delegate = self } @IBAction func Enter(_ sender: Any) { // 先校验输入不为空 guard let email = UserName.text, !email.isEmpty, let password = Password.text, !password.isEmpty else { TextView.text = "请输入完整的邮箱和密码" return } userEmail = email userPassword = password TextView.text = "Username: \(email)\nPassword: \(password)" // 获取访问令牌 teslaAPI.getAccessToken(email: email, password: password) { [weak self] (_, dataOrNil, errorOrNil) in guard let self = self else { return } if let error = errorOrNil { self.TextView.text = "获取令牌失败:\(error.localizedDescription)" return } guard let token = dataOrNil?.accessToken else { self.TextView.text = "未获取到有效访问令牌" return } self.accessToken = token self.teslaAPI.setAccessToken(token) // 获取车辆列表 self.teslaAPI.getVehicles { [weak self] (_, dataOrNil, errorOrNil) in guard let self = self else { return } if let error = errorOrNil { self.TextView.text = "获取车辆失败:\(error.localizedDescription)" return } guard let vehicle = dataOrNil?.vehicles.first else { self.TextView.text = "未找到关联的特斯拉车辆" return } self.vehicle = vehicle // 唤醒车辆成功后,再跳转页面 self.teslaAPI.wake(vehicle, completion: { [weak self] (success, _, error) in guard let self = self else { return } if let error = error { self.TextView.text = "唤醒车辆失败:\(error.localizedDescription)" return } guard success else { self.TextView.text = "车辆唤醒未成功,请稍后重试" return } // 所有数据就绪,执行跳转 self.performSegue(withIdentifier: "nextPage", sender: self) }) } } } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard let targetVC = segue.destination as? ViewController else { return } // 传递有效数据 targetVC.finalVehicle = vehicle targetVC.finalAccessToken = accessToken ?? "" targetVC.finalEmail = userEmail ?? "" targetVC.finalPassword = userPassword ?? "" } }
ViewController.swift
import UIKit class ViewController: UIViewController { // 修正车辆类型:用API返回的Vehicle对象,不是String var finalVehicle: Vehicle? var finalAccessToken = "" var finalEmail = "" var finalPassword = "" private let teslaAPI = TeslaAPI() @IBAction func chargeOffPeakSwitch(_ sender: UISwitch) { // 开关开启且车辆数据存在时才执行命令 guard sender.isOn, let targetVehicle = finalVehicle else { return } DispatchQueue.main.asyncAfter(deadline: .now() + 30.0) { [weak self] in guard let self = self else { return } // 使用正确的充电命令 let chargeCommand = Command.startCharging self.teslaAPI.send(chargeCommand, to: targetVehicle) { response in if response.result { print("Command sent successfully!") } else { print("命令执行失败:\(response.error?.localizedDescription ?? "未知错误")") } } } } }
额外注意事项
- 确保
Vehicle是特斯拉API库定义的正确类型,不要用String——API的send方法通常需要完整的车辆对象而非字符串 - 加入
[weak self]避免闭包循环引用,防止内存泄漏 - 增加了错误处理逻辑,能快速定位令牌获取、车辆唤醒等环节的问题
- 确认你的第三方API库的
Command枚举中确实包含startCharging选项
内容的提问来源于stack exchange,提问作者Ali
相关产品推荐
相关产品推荐

