iOS 10 - NSKeyValueObservation crash on deinit

Updated on 2019/10/16

This seems to still happen on iOS 10.3 with Xcode 11 and Swift 5.1, I created a sample project to test it by using code from SR-5752.

The easiest way I figure out so far is like so:

// Environment: Xcode 11.1, Swift 5.1, iOS 10.3
deinit {
    if #available(iOS 11.0, *) {} else if let observer = observer {
        removeObserver(observer, forKeyPath: "foo")
    }
} 

Can notice that I only call removeObserver(_:forKeyPath) on iOS 10 and lower because as Stacy Smith mentioned, this crash on iOS 13 (can be reproduced easily in the sample project).

I also tried Bryan Rodríguez's suggestion, but without luck. Maybe I missed something?

// Environment: Xcode 11.1, Swift 5.1, iOS 10.3
deinit {
    // Also tried only either one, no luck
    self.observer?.invalidate() 
    self.observer = nil
}

Looks like apple bug – https://bugs.swift.org/browse/SR-5816

This is happening because NSKeyValueObservation holds a weak reference to an object. That weak reference turns to nil too soon.

In some cases workaround can be found by using lifecycle methods (viewDidDissapear and such). In other cases you should use old obj-c api (addObserver / removeObserver / observeValue) to support iOS 10.