AVPlayer 已被释放,而关键值观察者仍向其注册

objective

1个回答

写回答

mumu1990

2025-06-18 11:40

+ 关注

IOS
IOS

IOS开发中,AVPlayer是一个常用的音视频播放器类。它提供了许多强大的功能,如播放、暂停、快进、音量控制等。在使用AVPlayer时,我们经常会使用关键值观察者来监听播放状态的变化,以便及时更新UI界面或做其他操作。然而,有时候我们可能会忘记在适当的时候取消对AVPlayer的观察,导致AVPlayer已被释放而观察者仍然保持注册的状态。这种情况下,如果观察者尝试访问已释放的AVPlayer对象,就会引发崩溃。本文将介绍这个问题的解决办法,并通过一个案例代码来演示。

## 问题描述

当AVPlayer对象被释放,而关键值观察者仍然注册在该对象上时,会发生什么情况呢?我们来看一个具体的案例。

Swift

import AVFoundation

class PlayerManager {

var player: AVPlayer?

init() {

player = AVPlayer()

player?.addObserver(self, forKeyPath: "status", options: .new, context: nil)

// 模拟一段时间后释放AVPlayer对象

DispatchQueue.mAIn.asyncAfter(deadline: .now() + 2) {

self.player = nil

}

}

deinit {

player?.removeObserver(self, forKeyPath: "status")

}

func play() {

// 模拟播放操作

player?.play()

}

func stop() {

// 模拟停止播放操作

player?.pause()

}

func observeValue(forKeyPath keyPath: String?,

of object: Any?,

change: [NSKeyValueChangeKey : Any]?,

context: UnsafeMutableRawPointer?) {

if keyPath == "status" {

guard let player = object as? AVPlayer else {

return

}

switch player.status {

case .readyToPlay:

print("Player is ready to play.")

case .fAIled:

print("Player fAIled to load.")

case .unknown:

print("Player status is unknown.")

@unknown default:

break

}

}

}

}

var playerManager: PlayerManager? = PlayerManager()

playerManager?.play()

// 模拟一段时间后,playerManager对象被释放

DispatchQueue.mAIn.asyncAfter(deadline: .now() + 5) {

playerManager = nil

}

在上述代码中,我们创建了一个PlayerManager类来管理AVPlayer对象。在初始化过程中,我们创建了一个AVPlayer对象,并向其注册了一个关键值观察者,观察"status"属性的变化。然后,我们使用该AVPlayer对象进行播放操作。之后,我们模拟了一段时间后释放了AVPlayer对象,也就是将其置为nil。最后,我们又模拟了一段时间后将playerManager对象置为nil,以触发其释放。

## 问题分析

当AVPlayer对象被释放时,我们期望关键值观察者也能够被自动取消注册,这样就不会再触发之后的回调方法了。然而,在上述代码中,我们没有手动取消关键值观察者的注册,而是依赖于PlayerManager对象的释放来自动取消注册。这就导致了一个问题:如果我们忘记将PlayerManager对象置为nil,或者在适当的时机手动取消关键值观察者的注册,那么AVPlayer对象将会一直被观察,即使它已经被释放了。

## 解决办法

为了解决这个问题,我们需要在适当的时机手动取消关键值观察者的注册。在上述代码中,我们选择在PlayerManager对象的deinit方法中取消关键值观察者的注册。这样,在PlayerManager对象被释放时,关键值观察者也会被自动取消注册,不会再触发之后的回调方法。

Swift

deinit {

player?.removeObserver(self, forKeyPath: "status")

}

上述代码中,我们使用removeObserver(_:forKeyPath:)方法来取消关键值观察者的注册。该方法需要传入观察者对象和观察的属性的名称。在我们的例子中,观察者对象就是PlayerManager对象自身,观察的属性名称是"status"。

通过在适当的时机手动取消关键值观察者的注册,我们可以避免AVPlayer对象已被释放而观察者仍然保持注册的问题。这样,就能够保证代码的健壮性和稳定性。

IOS开发中,AVPlayer是一个常用的音视频播放器类。在使用AVPlayer时,我们经常会使用关键值观察者来监听播放状态的变化。然而,有时候我们可能会忘记在适当的时候取消对AVPlayer的观察,导致AVPlayer已被释放而观察者仍然保持注册的状态。为了解决这个问题,我们可以在适当的时机手动取消关键值观察者的注册。这样,就能够避免观察者访问已释放的AVPlayer对象而引发崩溃的情况发生。通过这种方式,我们可以提高代码的健壮性和稳定性,从而提升用户体验。

举报有用(4分享收藏

Copyright © 2025 IZhiDa.com All Rights Reserved.

知答 版权所有 粤ICP备2023042255号