SwiftUI视图出现时播放视频报错,如何等待资源加载后播放?
解决AVPlayer主线程阻塞问题:等待资源加载完成再播放
你遇到的错误是因为远程视频资源未加载完成时就调用了play(),导致主线程同步查询未就绪的媒体属性(PreferredTransform)被阻塞,慢速网络下问题会更突出。解决核心是监听AVPlayerItem的加载状态,等资源真正准备好后再触发播放。
核心思路
- 改用
AVPlayerItem管理远程媒体资源,替代直接用URL初始化AVPlayer的方式 - 监听
AVPlayerItem的status属性,仅当状态变为.readyToPlay时执行播放 - 避免视图刚出现时强制播放,让资源加载完成后自动触发播放逻辑
修改后的完整代码
import SwiftUI import AVKit import Combine struct MainVideoPlayer: View { let url: URL @State private var player: AVPlayer? @State private var cancellables = Set<AnyCancellable>() var body: some View { ZStack { VideoPlayer(player: $player) } .onAppear { setupPlayer() } .onDisappear { // 清理资源,避免内存泄漏 player?.pause() player = nil cancellables.removeAll() } } private func setupPlayer() { let playerItem = AVPlayerItem(url: url) // 用Combine监听playerItem的状态变化 playerItem.publisher(for: \.status) .receive(on: DispatchQueue.main) .sink { [weak self] status in guard let self = self else { return } switch status { case .readyToPlay: // 资源准备完成,开始播放 self.player?.play() case .failed: // 处理加载失败场景 if let error = playerItem.error { print("视频加载失败: \(error.localizedDescription)") } case .unknown: // 资源加载中,等待即可 break @unknown default: break } } .store(in: &cancellables) // 初始化player并关联playerItem player = AVPlayer(playerItem: playerItem) } } struct VideoPlayer: UIViewControllerRepresentable { @Binding var player: AVPlayer? func makeUIViewController(context: Context) -> AVPlayerViewController { let controller = AVPlayerViewController() controller.showsPlaybackControls = false controller.videoGravity = .resizeAspectFill return controller } func updateUIViewController(_ uiViewController: AVPlayerViewController, context: Context) { // 当player实例变化时更新控制器关联的player uiViewController.player = player } }
关键修改点说明
- AVPlayerItem管理资源:通过
AVPlayerItem可精准监听媒体加载状态,避免直接操作AVPlayer导致的主线程同步阻塞 - Combine状态监听:利用Combine框架监听
status属性变化,确保在主线程处理状态回调,保证UI操作安全 - 资源清理:在视图消失时暂停播放并释放player,避免内存泄漏
- 错误处理:添加加载失败的逻辑分支,方便后续扩展用户提示
额外优化建议
- 可在资源加载中(
status为.unknown时)添加加载指示器,提升用户体验 - 若需支持缓存,可通过
AVAssetResourceLoader实现自定义资源加载逻辑
内容的提问来源于stack exchange,提问作者Ahmed Zaidan
相关产品推荐
相关产品推荐

