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

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.12 05:15:33