Swift Observer (KVO): Checking for Existence

Viewed 5056

I have a box that the user is able to pan around. For that, I add an observer to check if it's center has changed:

self.boxView!.addObserver(self, forKeyPath: "center", options: .old, context: &BoxCenterContext)

This gets added after an animation that presents the box.

When the box dismisses, I remove it as this:

self.boxView!.removeObserver(self, forKeyPath: "center", context: &BoxCenterContext)

Issue

There is a possibility of the user being able to dismiss the box before box presentation has been completed, ie. before the KVO is added.

When that happens, the app crashes trying to remove a KVO that does not exist.

Question

Is there a way to check for existence of KVO (before trying to remove)?

4 Answers

observationInfo property is set when there is an observer added

if self.boxView!.observationInfo != nil {

   self.boxView!.removeObserver(self, forKeyPath: "center", context: &BoxCenterContext) 
}

Apple does not provide any API for check existence of observer but you can manage a Bool flag for this. Like when u register KVO you set isObserver bool to true and then before removing observer you need to check isObserver true of false if isObserver is true so remove observer and if it's false don't do any thing.

Use this extension

extension NSObject {
  func safeRemoveObserver(_ observer: NSObject, forKeyPath keyPath: String) {
    switch self.observationInfo {
    case .some:
      self.removeObserver(observer, forKeyPath: keyPath)
    default:
      debugPrint("observer does no not exist")
    }
  }
}

According to Apple doc observer removal code should be wrapped in a @try @catch block, because there is no API to check whether a particular object is an observer. For example (forgive me objective c please):

    @try {
        [self.event removeObserver:self forKeyPath:@"eventTimeZone"];
    } @catch (NSException *exception) {
        NSLog(@"Tried to remove observer from event, but there was no observer anymore.");
    }
Related