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

如何缓存WKWebView内容以解决UICollectionView滚动时的卡顿问题

卡顿原因分析

当前滚动卡顿不止是WKWebView缓存的问题,你的现有代码本身存在大量重复渲染操作,也是卡顿的核心诱因:

  • changeToShadowedCard()方法被放在layoutSubviews中执行,该方法会重复向contentView添加borderView、重复添加约束,多余的渲染操作会大量占用主线程资源
  • UISetUp()每次video属性赋值都会重复添加videoView到borderView、重复添加约束,cell复用时会强制重新加载视频,无法复用已有加载内容
  • WKWebView默认缓存策略未适配视频场景,滚动时新出现的cell都要重新请求YouTube资源,进一步阻塞主线程
优化方案

一、修复代码重复操作问题

调整cell初始化逻辑,视图添加、约束配置仅执行一次,不要在布局回调和属性监听中重复执行:

import UIKit
import YouTubePlayer_Swift

class YouTubeVideoCollectionViewCell: UICollectionViewCell {
    
    let borderView = UIView(frame: .zero)
    var videoView = YouTubePlayerView(frame: .zero)
    
    var video: YouTubeVideo? {
        didSet {
            // 仅做视频加载逻辑,相同id不重复加载
            guard let id = video?.id, videoView.videoID != id else { return }
            videoView.loadVideoID(id)
        }
    }
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        setupBaseViews()
    }
    
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        setupBaseViews()
    }
    
    // 基础视图配置仅执行一次
    private func setupBaseViews() {
        backgroundColor = .clear
        // 配置borderView
        contentView.addSubview(borderView)
        borderView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            borderView.topAnchor.constraint(equalTo: self.contentView.topAnchor),
            borderView.bottomAnchor.constraint(equalTo: self.contentView.bottomAnchor),
            borderView.rightAnchor.constraint(equalTo: self.contentView.rightAnchor),
            borderView.leftAnchor.constraint(equalTo: self.contentView.leftAnchor),
        ])
        borderView.layer.masksToBounds = true
        borderView.backgroundColor = UIColor.secondarySystemBackground
        borderView.layer.cornerRadius = 5
        borderView.addShadow(shadowColor: UIColor.label.cgColor, shadowOffset: CGSize(width: 0, height: 0), shadowOpacity: 0.6, shadowRadius: 3)
        
        // 配置videoView
        borderView.addSubview(videoView)
        videoView.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            videoView.topAnchor.constraint(equalTo: borderView.topAnchor),
            videoView.bottomAnchor.constraint(equalTo: borderView.bottomAnchor),
            videoView.rightAnchor.constraint(equalTo: borderView.rightAnchor),
            videoView.leftAnchor.constraint(equalTo: borderView.leftAnchor),
        ])
        videoView.clipsToBounds = true
        videoView.layer.cornerRadius = 5
    }
    
    override open func preferredLayoutAttributesFitting(_ layoutAttributes: UICollectionViewLayoutAttributes) -> UICollectionViewLayoutAttributes {
        self.updateConstraintsIfNeeded()
        return super.preferredLayoutAttributesFitting(layoutAttributes)
    }
    
    override func layoutSubviews() {
        super.layoutSubviews()
        self.contentView.layoutIfNeeded()
    }
}

二、开启WKWebView全局缓存

在AppDelegate的didFinishLaunchingWithOptions方法中添加全局缓存配置,适配视频资源缓存需求:

// 配置100MB内存缓存、500MB磁盘缓存
let memoryCacheSize = 100 * 1024 * 1024
let diskCacheSize = 500 * 1024 * 1024
WKWebsiteDataStore.default().removeData(ofTypes: [WKWebsiteDataTypeDiskCache, WKWebsiteDataTypeMemoryCache], modifiedSince: Date.distantPast) {
    URLCache.shared = URLCache(memoryCapacity: memoryCacheSize, diskCapacity: diskCacheSize, diskPath: "youtubeVideoCache")
}

同时可以修改YouTubePlayerView内部的加载请求,将请求缓存策略改为returnCacheDataElseLoad,优先读取本地缓存,无缓存再发起网络请求。

三、补充滚动优化

如果列表视频数量较多,可以额外增加两个逻辑进一步降低卡顿:

  • 预加载即将进入屏幕的2-3个cell的视频资源,不要等cell完全显示再触发加载
  • 滚动速度较快时暂停新的视频加载,等滚动减速停止后再加载当前可见区域的视频资源

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 00:45:03