如何缓存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
相关产品推荐
相关产品推荐

