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

Collection View未展示预期相似电影数据问题求助

问题排查与修复方案

1. 视图层级错误(核心问题)

CommonViewController的combineView方法逻辑完全错误:

  • 错误创建了新的CommonViewController实例,未使用当前控制器作为容器
  • 仅调用addChild添加子控制器,但未将子控制器的view添加到父视图,也未完成子控制器生命周期的关联(如didMove(toParent:))

修复代码:

private func combineView() {
    let dvc = MovieDetailsViewController(viewModel: viewModel)
    let svc = SmiliarMovieViewController(viewModel: viewModel)
    
    // 添加子控制器到当前CommonViewController
    addChild(dvc)
    addChild(svc)
    
    // 将子视图添加到当前控制器的view
    view.addSubview(dvc.view)
    view.addSubview(svc.view)
    
    // 设置子视图约束(可根据需求调整布局)
    dvc.view.translatesAutoresizingMaskIntoConstraints = false
    svc.view.translatesAutoresizingMaskIntoConstraints = false
    
    NSLayoutConstraint.activate([
        dvc.view.topAnchor.constraint(equalTo: view.topAnchor),
        dvc.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
        dvc.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
        dvc.view.bottomAnchor.constraint(equalTo: svc.view.topAnchor),
        
        svc.view.leadingAnchor.constraint(equalTo: view.leadingAnchor),
        svc.view.trailingAnchor.constraint(equalTo: view.trailingAnchor),
        svc.view.bottomAnchor.constraint(equalTo: view.bottomAnchor),
        svc.view.heightAnchor.constraint(equalToConstant: view.frame.width/2)
    ])
    
    // 完成子控制器生命周期关联
    dvc.didMove(toParent: self)
    svc.didMove(toParent: self)
}

2. ViewModel数据更新顺序错误

fetchSimilarMovie中先更新state触发回调,再赋值moviePage,导致回调执行时moviePage仍为空数组,collectionView reload后无数据。

修复代码:

func fetchSimilarMovie() {
    apiManager.execute(Movie.similiar(for: initialMovie.id)) { [weak self] result in
        guard let self = self else { return }
        switch result {
        case.success(let page):
            // 先赋值数据,再更新state触发回调
            self.moviePage = page.results
            self.state = .pageLoaded(page)
        case .failure(let error):
            self.state = .error
            print(error)
        }
    }
}

3. Cell标识符不匹配(潜在问题)

SimilierMovieCell的静态标识符定义为"CompanyCell",与类名不符易混淆,建议修正:

class SimilierMovieCell: UICollectionViewCell {
    static let identifier = "SimilierMovieCell"
    // ... 其他代码
}

4. Cell重复添加子视图(性能与显示问题)

每次调用configure都向contentView添加companyImageView,复用cell时会重复添加视图导致布局混乱,应将添加子视图的代码移至cell初始化方法:

class SimilierMovieCell: UICollectionViewCell {
    static let identifier = "SimilierMovieCell"
    
    private lazy var companyImageView: UIImageView = {
        let imageView = UIImageView()
        imageView.translatesAutoresizingMaskIntoConstraints = false
        imageView.contentMode = .scaleAspectFit
        return imageView
    }()
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupViews()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    private func setupViews() {
        contentView.addSubview(companyImageView)
        let safeArea = contentView.safeAreaLayoutGuide
        NSLayoutConstraint.activate([
            companyImageView.topAnchor.constraint(equalTo: safeArea.topAnchor),
            companyImageView.bottomAnchor.constraint(equalTo: safeArea.bottomAnchor),
            companyImageView.leadingAnchor.constraint(equalTo: safeArea.leadingAnchor),
            companyImageView.trailingAnchor.constraint(equalTo: safeArea.trailingAnchor)
        ])
    }
    
    func configure(movieDetails: Movie) {
        if let path = movieDetails.posterPath {
            companyImageView.dm_setImage(posterPath: path)
        } else {
            companyImageView.image = nil
        }
    }
}

5. 图片下载强制解包(崩溃风险)

dm_setImage中强制解包imageURL!,若URL无效会导致崩溃,改为可选绑定:

extension UIImageView {
    func dm_setImage(posterPath: String) {
        guard let imageURL = URL(string: "https://image.tmdb.org/t/p/w185/\(posterPath)") else {
            self.image = nil
            return
        }
        DispatchQueue.global().async {
            guard let data = try? Data(contentsOf: imageURL) else {
                DispatchQueue.main.async {
                    self.image = nil
                }
                return
            }
            DispatchQueue.main.async {
                self.image = UIImage(data: data)
            }
        }
    }
}

额外优化建议

  • 避免使用Data(contentsOf:)进行网络请求,推荐用URLSession(同步请求无超时处理,易阻塞线程)
  • 为collectionView添加占位图,处理无数据或图片加载失败的场景
  • 实现图片缓存机制,避免重复网络请求

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.29 16:01:12