3

I have a video app that I built a while back in Swift 1 and I've been trying to migrate to Swift 2.2. It all (finally) works apart from a weird crash to do with observers.

func removeObservers()
{
    print("REMOVING OBSERVERS")
    if ( !self.is_image && self.player != nil  ) {
        if (self.player?.observationInfo != nil) {

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

        }
    }
    NSNotificationCenter.defaultCenter().removeObserver(self)

}

This worked previously using SwiftTryCatch but with the lines in place crashes with "'Cannot remove an observer for the key path "readyForDisplay" from because it is not registered as an observer.'" OR with that an observer is registered on a deallocated object if I comment it out.

If I add a do { } catch {} to it I get an error that "this does not throw" and it just crashes the same. How do I go about putting this in some form of try-catch format?

Reinier Melian
  • 20,519
  • 3
  • 38
  • 55
Martin
  • 1,135
  • 1
  • 8
  • 19
  • I had a problem very similar to this. Do you remove that observer in any other part of your code? The easiest way might be to unify where you create and remove observers... I was removing readyForDisplay after it displayed, but then couldn't remove it when dealloc came around. – Putz1103 Jun 14 '16 at 17:37

3 Answers3

5

In Swift 2, the libs got annoyingly strict about errors that are truly unexpected (which throw) versus errors that the programmer could have prevented (which do not throw, but just crash your app).

(I’m not a fan of this distinction, or at least not of all the specific decisions Apple made about which errors fall in which category. The JSON API verges on the nonsensical in this department. But…we work with the API we’ve got.)

The NSKeyValueObserving docs say:

It is an error to call removeObserver:forKeyPath: if the object has not been registered as an observer.

“It is an error” is Apple code for “you are responsible for never doing this, and if you do, your app will crash in an uncatchable way.”

In these situations, there is usually an API call you can make to check the validity of the thing you’re about to do. However, AFAIK, there’s no KVO API call you can make to ask, “Is X observing key path Y of object Z?” That means you have three options:

  • Figure out why you’re trying to remove an observer from something you’re not observing, and prevent that using your program’s own internal logic.
  • Keep a weak instance var for “player I’m observing,” and check that for a match before attempting to remove the observer.
  • Add self as an observer before removing it. (I’m pretty sure that a redundant add is OK.)
Paul Cantrell
  • 9,175
  • 2
  • 40
  • 48
  • I tried adding a boolean to say that the observers are set and realised that thy were being removed twice in some cases so that fixed it. Thanks. – Martin Jun 15 '16 at 11:50
0

Since you are making a call removeObserver(self) at the end of the method, why cant you uncomment above code? Because removeObserver(self) removes all the observers if registered any. I hope this solves your issue.

NSNotificationCenter.defaultCenter().removeObserver(self)
Santosh
  • 2,900
  • 1
  • 16
  • 16
0

status is a property of either AVPlayer or AVPlayerItem.

readyForDisplay is a property of AVPlayerLayer

Shingo Fukuyama
  • 1,492
  • 1
  • 17
  • 19