Search code examples
iosswiftavplayeravplayeritem

App crashes sometimes when removing observer from AVPlayer


I'm working on something similar to TikTok App, So I have a ScrollView and multiple custom UIView inside the scrollView, On viewDidLoad I'm initializing all required views to prepare the videos.

Every view has its own AVPlayer and its own observers like this:

playerItem?.addObserver(self, forKeyPath: "status", options: [.old, .new], context: safeAudioItemPointer)
player?.addObserver(self, forKeyPath: "timeControlStatus", options: [.old, .new], context: safeAudioPlayerPointer)

So when the user wants to leave the controller I simply remove the observers for each view in this way:

if let playerItem = self.playerItem, let asset = self.asset, let player = self.player {

        asset.cancelLoading()
        playerItem.cancelPendingSeeks()

        if playerItem.observationInfo != nil {
            playerItem.removeObserver(self, forKeyPath: "status", context: self.safeAudioItemPointer)
        }

        if player.observationInfo != nil {
            player.removeObserver(self, forKeyPath: "timeControlStatus", context: self.safeAudioPlayerPointer)
        }

        player.cancelPendingPrerolls()
        player.replaceCurrentItem(with: nil)

        stop()
    }

My problem that is sometimes the "timeControlStatus" observer is not registered, so the app crashes and I didn't find a way to check if that observer is already registered or not.

In addition, I can't depend on deinit() override method, because sometimes I need to remove the observers without closing the controller.

I'm working on Swift 3, any idea could be helpful.

Thanks.


Solution

  • You can deal with: NSKeyValueObservation

    var observer: NSKeyValueObservation?
    
    self.observer = myPlayer.observe(\.rate, options:  [.new, .old], changeHandler: { (player, change) in
         if player.rate == 1  {
              print("Playing")
          }else{
               print("Stop")
          }
     })
    
     // Later You Can Remove Observer      
     self.observer?.invalidate()
     self.observer = nil