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

iOS页面传值异常:AgentDetailVC至AbilitiesDetailsVC传值为空

iOS页面传值问题排查:AgentDetailVC到AbilitiesDetailsViewController传值为空

问题描述

在iOS开发中,从AgentDetailVC向AbilitiesDetailsViewController传递数据时,所有传递的数据均为nil或空字符串。此前已成功实现AgentListVC到AgentDetailVC的传值,请求排查代码并解决问题。


涉及代码

AgentListVC代码

import UIKit

class AgentListVC: UIViewController {
    var agentsReference = ValorantReferenceApp().agents
    @IBOutlet var tableView: UITableView!
    override func viewDidLoad() {
        self.tableView.rowHeight = 100
        tableView.delegate = self
        tableView.dataSource = self
        super.viewDidLoad()
        configureNavigationBar()
    }
    //MARK: - Configure Navigation Bar
    func configureNavigationBar() {
        self.navigationController?.navigationBar.prefersLargeTitles = true
        if var textAttributes = navigationController?.navigationBar.titleTextAttributes {
            textAttributes[NSAttributedString.Key.foregroundColor] = UIColor.red
            navigationController?.navigationBar.titleTextAttributes = textAttributes
        }
    }
}
//MARK: - Table View Methods
extension AgentListVC: UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return agentsReference.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell1", for: indexPath) as! AgentCellVC
        let agent = agentsReference[indexPath.row]
        cell.agentNameLAbel.text = agent.name
        cell.agentImageview.image = agent.iconAgent
        return cell
    }
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        performSegue(withIdentifier: "toSecondVC", sender: nil)
    }
    //MARK: - Prepare Segue
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        let destinationVC = segue.destination as! AgentDetailVC
        if let indexPath = tableView.indexPathForSelectedRow {
            let agent = agentsReference[indexPath.row]
            destinationVC.agentDetailVariables.choosenFlagImage = agent.agentFlagImage
            destinationVC.agentDetailVariables.choosenAgentIconImage = agent.iconAgent
            destinationVC.agentDetailVariables.choosenAgentType = agent.type.rawValue
            destinationVC.agentDetailVariables.choosenAgentName = agent.name
            destinationVC.choosenAgentAbilities = agent.abilities
            destinationVC.agentDetailVariables.choosenAgentAbilitiesImages = agent.agentAbilitiesImage
            destinationVC.choosenAgentVideoLink = agent.skillAbilitiesLink
        }
    }
}

AgentDetailVC代码

import UIKit

class AgentDetailVC: UIViewController {
    @IBOutlet var typeLabel: UILabel!
    @IBOutlet var characterImageView: UIImageView!
    @IBOutlet var flagImageView: UIImageView!
    @IBOutlet var tableView: UITableView!
    @IBOutlet var agentTypeImageView: UIImageView!
    var agentDetailVariables = AgentDetailVariables()
    var agentsReference = ValorantReferenceApp().agents
    var choosenAgentAbilities = [String]()
    var viewController = AbilitiesDetailsViewController()
    var choosenAgentVideoLink = [String]()
    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.delegate = self
        tableView.dataSource = self
        viewLoad()
        print(choosenAgentAbilities)
    }
    //MARK: - ViewLoad Function.
    func viewLoad() {
        flagImageView.image = agentDetailVariables.choosenFlagImage
        characterImageView.image = agentDetailVariables.choosenAgentIconImage
        typeLabel.text = agentDetailVariables.choosenAgentType
        title = agentDetailVariables.choosenAgentName
        tableView.rowHeight = 65
        tableView.separatorStyle = .none
        agentTypeImageView.image = UIImage(named: "\(agentDetailVariables.choosenAgentType)")
    }
}
//MARK: - TableView Methods
extension AgentDetailVC : UITableViewDelegate, UITableViewDataSource {
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return choosenAgentAbilities.count
    }
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "cell2", for: indexPath) as! AgentDetailsCellVC
        let agentAbilities = choosenAgentAbilities[indexPath.row]
        let skillImages = agentDetailVariables.choosenAgentAbilitiesImages[indexPath.row]
        print(agentAbilities)
        cell.skillNameLabel.text = agentAbilities
        cell.skillImageView.image = skillImages
        return cell
    }
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        tableView.deselectRow(at: indexPath, animated: true)
        performSegue(withIdentifier: "toYoutubeVideos", sender: nil)
    }
    override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
        if segue.identifier == "toYoutubeVideos" {
            let destinationVC = segue.destination as! AbilitiesDetailsViewController
            if let indexPath = tableView.indexPathForSelectedRow {
                let agent = agentsReference[indexPath.row]
                let link = choosenAgentVideoLink[indexPath.row]
                print(link)
                destinationVC.agentAbilitiesVideoURL = link
                destinationVC.choosenAgentSkillName = choosenAgentAbilities[indexPath.row]
            }
        }
    }
}

AbilitiesDetailsViewController代码

import UIKit
import AVKit
import AVFoundation
import MediaPlayer
import MobileCoreServices
import YoutubePlayer_in_WKWebView

class AbilitiesDetailsViewController: UIViewController, AVPlayerViewControllerDelegate {
    @IBOutlet var skillDetailsLabel: UILabel!
    @IBOutlet var skillNameLabel: UILabel!
    @IBOutlet var heroIconImageView: UIImageView!
    var agentAbilitiesVideoURL = ""
    var choosenAgentSkillName = ""
    override func viewDidLoad() {
        skillNameLabel.text = choosenAgentSkillName
        super.viewDidLoad()
    }
    @IBAction func playVideoUsingURL(_ sender: Any) {
        playGlobalVideo()
    }
    func playGlobalVideo() {
        guard let videoURL = URL(string: agentAbilitiesVideoURL ?? "sad") else {
            return
        }
        let player = AVPlayer(url: videoURL)
        let vc = AVPlayerViewController()
        vc.player = player
        present(vc, animated: true) {
            player.play()
        }
    }
    func playAbilitiesVideos() {
        let player = AVPlayer(url: URL(string: "https://assets.contentstack.io/v3/assets/bltb6530b271fddd0b1/bltf4e7a6525fe6ec42/625f2c7cfd9afd4b1fe300ee/C-Prowler_video.mp4")!)
        let controller = AVPlayerViewController()
        present(controller, animated: true) {  }
        controller.player = player
        addChild(controller)
        view.addSubview(controller.view)
        controller.view.frame = CGRect(x: 50 , y: 50, width: 300, height: 300)
        controller.player = player
        controller.showsPlaybackControls = true
        player.isClosedCaptionDisplayEnabled = false
        player.play()
    }
}

结构体代码

struct Agent: Hashable{
    let name: String
    let type: AgentType
    let origin: String
    let abilities: [String]
    let iconAgent : UIImage
    let agentFlagImage : UIImage
    let agentAbilitiesImage: [UIImage]
    let skillAbilitiesLink: [String]
}

enum AgentType:String{
    case controller = "Controller"
    case sentinel = "Sentinel"
    case initiator = "Initiator"
    case duelist = "Duelist"
}

ValorantReferenceApp代码

struct ValorantReferenceApp {
    static var agentIconImages = AgentIconImages()
    static var agentFlagImages = AgentFlagImages()
    static var agentAbilitiesImages = AgentAbilitiesImages()
    var agents: [Agent] =  [
        Agent(name: "Brimstone", type: .controller, origin: "United States", abilities: ["Incendiary",
                                                                                         "Stim Beacon",
                                                                                          "Sky Smoke",
                                                                                          "Orbital Strike"],
              iconAgent: agentIconImages.iconBrimstone!,
              agentFlagImage: agentFlagImages.flagBrimstone!,
              agentAbilitiesImage: agentAbilitiesImages.abilitiesBrimstone, skillAbilitiesLink:
                ["https://assets.contentstack.io/v3/assets/bltb6530b271fddd0b1/blte2b9eb1923ef64fa/5ecad7d0f5bd13348a6cac75/Brimstone_Q_v001_web.mp4",
                    "https://assets.contentstack.io/v3/assets/bltb6530b271fddd0b1/bltc34c3d692ea83f41/5ecad7d0177c51692beb1fe4/Brimstone_C_v001_web.mp4",
                    "https://assets.contentstack.io/v3/assets/bltb6530b271fddd0b1/bltcf4359fed083686b/5ecad7d198f79d6925dbee07/Brimstone_E_v001_web.mp4",
                    "https://assets.contentstack.io/v3/assets/bltb6530b271fddd0b1/blt3d19d83ba51eb18f/5ecad7d297b46c1911ad1868/Brimstone_X_v001_web.mp4"
                ])
    ]
}

问题根源与修复方案

1. 核心问题:传值时错误获取Agent数据

在AgentDetailVC的prepare(for:sender:)方法中,你错误地通过agentsReference[indexPath.row]获取Agent实例,但这里的indexPath是技能列表的行索引,不是Agent列表的索引。当前AgentDetailVC展示的是单个Agent的技能列表,无需重新从Agent列表中取数据,直接使用已有的choosenAgentVideoLink和choosenAgentAbilities数组即可。

2. 次要问题:字符串可选绑定错误

AbilitiesDetailsViewController的playGlobalVideo()方法中,agentAbilitiesVideoURL是默认空字符串的非可选类型,不需要用?? "sad"进行可选绑定,直接传入即可。

修复后的关键代码

修复AgentDetailVC的prepare(for:sender:)方法

override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    if segue.identifier == "toYoutubeVideos" {
        let destinationVC = segue.destination as! AbilitiesDetailsViewController
        if let indexPath = tableView.indexPathForSelectedRow {
            // 直接使用当前VC已保存的技能数据
            let link = choosenAgentVideoLink[indexPath.row]
            print(link)
            destinationVC.agentAbilitiesVideoURL = link
            destinationVC.choosenAgentSkillName = choosenAgentAbilities[indexPath.row]
        }
    }
}

修复AbilitiesDetailsViewController的playGlobalVideo()方法

func playGlobalVideo() {
    guard let videoURL = URL(string: agentAbilitiesVideoURL) else {
        print("无效视频链接:\(agentAbilitiesVideoURL)")
        return
    }
    let player = AVPlayer(url: videoURL)
    let vc = AVPlayerViewController()
    vc.player = player
    present(vc, animated: true) {
        player.play()
    }
}

额外优化建议

  • 删除AgentDetailVC中冗余的var viewController = AbilitiesDetailsViewController()声明,该实例不会被Segue使用,属于无效代码。
  • 可以将agentAbilitiesVideoURL和choosenAgentSkillName改为可选类型(如String?),避免空字符串引发的潜在问题。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.03 08:25:32