我在通过预先创建(持久)AVPlayerItem并将它们分配给(新的/临时的)AVPlayer来构建视频预加载时遇到了一个问题。
我看到的第一个问题是,如果以前分配给AVPlayer的AVPlayerItem被分配给新的AVPlayer,它将抛出异常。后来我将范围缩小到原来的AVPlayer没有被释放,这就是为什么AVPlayerItem不能与不同的播放器一起工作的原因“一个AVPlayerItem不能与多个AVPlayer实例相关联”。
下面是最小的可重现示例:
// AVAsset can be preloaded using `asset.loadValuesAsynchronously`.
let originalAsset = AVAsset(url: URL(string: "https://www.whatever.com")!)
// AVPlayerItem is persisted across multiple AVPlayer instances.
let playerItem = AVPlayerItem(asset: originalAsset)
// Initial preload.
var player: AVPlayer? = AVPlayer(playerItem: playerItem)
player?.replaceCurrentItem(with: nil) // Doesn't help.
player = nil // Doesn't actually deinit.
// Later at some point...
player = AVPlayer(playerItem: playerItem) // Crash here.发布于 2021-02-20 01:13:12
解决方案是确保AVPlayerItem和AVPlayer具有1:1的关系,方法是在需要将其分配给AVPlayer时创建一个新的AVPlayerItem。这是因为在AVPlayer上设置AVPlayerItem会在两者之间创建隐藏的强引用,因此持久化AVPlayerItem将挂起AVPlayer,从而导致内存泄漏。
以下是几个工作示例:
// AVAsset can be preloaded using `asset.loadValuesAsynchronously`.
let originalAsset = AVAsset(url: URL(string: "https://www.whatever.com")!)
// AVPlayerItem is persisted across multiple AVPlayer instances.
// This is not necessary if you can persist the AVAsset instead (example below).
let playerItem = AVPlayerItem(asset: originalAsset)
// Initial preload.
var player = AVPlayer(playerItem: playerItem)
// Later at some point...
// Because a new `AVPlayerItem` is created, the previous one can be deallocated
// along with the `AVPlayer` instance.
player = AVPlayer(playerItem: AVPlayerItem(asset: originalAsset))
// Some alternatives that also work:
player = AVPlayer(playerItem: AVPlayerItem(asset: playerItem.asset))
player = AVPlayer(playerItem: playerItem.copy() as? AVPlayerItem)https://stackoverflow.com/questions/66282060
复制相似问题