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

UICollectionView自定义Cell如何通过Segue传值到PlayerViewController

问题修复方案

你现有代码存在几个核心逻辑错误:

  • 代理方法未携带选中的Video对象,无法传递点击的视频数据
  • 代理遵守方错误:跳转逻辑属于控制器职责,不应由目标页PlayerViewController遵守代理执行跳转
  • prepare(for:sender:)方法位置错误:该方法仅在发起跳转的源控制器上触发,写在目标控制器里永远不会执行
  • 传值逻辑错误:不能在跳转前直接访问目标控制器的UI控件(此时控件未初始化,为nil),且sender参数未传递选中的视频对象

分步修改步骤

1. 修改代理协议,补充视频参数

把原来无参的代理方法改成带Video参数,用于传递点击的视频对象:

import UIKit

protocol FirstPlaylistCollectionViewDelegate: AnyObject {
    // 新增Video参数用于传递选中的视频
    func playVideo(_ video: Video)
}

2. 修改CollectionView的点击回调,传递选中视频

在FirstPlaylistCollectionView的didSelectItemAt方法里,取出选中的视频,通过代理传递出去:

func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
    let selectedVideo = firstPlaylist[indexPath.row]
    // 把选中的视频传给代理方
    self.delegate2?.playVideo(selectedVideo)
    print("selected video \(selectedVideo) with \(collectionView)! DONE!")
}

3. 在持有CollectionView的主控制器中遵守代理

你添加三个横向CollectionView的主ViewController(下称HomeViewController)才是执行跳转的正确位置,不要在PlayerViewController里实现代理:

  • 首先在主控制器初始化FirstPlaylistCollectionView的位置,设置代理:
// 初始化FirstPlaylistCollectionView后补充这行
firstPlaylistCollectionView.delegate2 = self
  • 然后在主控制器中实现代理方法,触发跳转,把选中的视频作为sender参数传入:
extension HomeViewController: FirstPlaylistCollectionViewDelegate {
    func playVideo(_ video: Video) {
        // sender直接传选中的video对象,不要传self
        performSegue(withIdentifier: "homeToPlayer", sender: video)
    }
}

4. 实现跳转前的传值逻辑

把原来写在PlayerViewController里的prepare(for:sender:)方法删掉,移到主控制器HomeViewController中,仅给目标控制器的属性赋值,不要直接操作UI:

// 该方法必须写在发起跳转的HomeViewController中
override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
    guard segue.identifier == "homeToPlayer",
          let playerVC = segue.destination as? PlayerViewController,
          let selectedVideo = sender as? Video else {
        return
    }
    // 只给目标控制器的存储属性赋值,不要直接访问UI控件
    playerVC.video = selectedVideo
}

5. 清理PlayerViewController中的错误代码

删掉PlayerViewController里错误的prepare方法、错误的代理扩展,在viewDidLoad中用传递过来的video数据更新UI:

import UIKit
import WebKit

class PlayerViewController: UIViewController {

    @IBOutlet weak var handleArea: UIView!
    @IBOutlet weak var openCloseArrow: UIImageView!
    @IBOutlet weak var titleOfVideoLabel: UILabel! // 补上你原来缺失的标题控件输出口

    var video: Video?

    override func viewDidLoad() {
        super.viewDidLoad()
        // 等页面加载完成再给UI赋值
        titleOfVideoLabel.text = video?.title
        // 其余播放器初始化、加载视频逻辑写在这里
    }
}

补充:纯代码跳转方案(不用Storyboard Segue)

如果你后续要完全去掉Storyboard,直接在代理方法里初始化控制器传值即可,不用写performSegue和prepare方法:

// 主控制器里的代理方法
func playVideo(_ video: Video) {
    let playerVC = PlayerViewController()
    playerVC.video = video
    // 导航栈跳转用这个
    navigationController?.pushViewController(playerVC, animated: true)
    // 模态弹出用这个
    // present(playerVC, animated: true)
}

注意:如果用纯代码初始化PlayerViewController,原来的@IBOutlet会失效,需要把相关UI控件改成纯代码布局实现。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 13:03:21