NSKeyValueObservingCustomization Is Fundamentally Broken
The breakage is the fact that implementing it relies on being able to do equality testing on key paths, but equality testing on key paths doesn’t work in the face of subclassing. By that I mean given the following code
class Foo: NSObject { @objc dynamic var name: String? } class Bar: Foo {}The expression
\Foo.name == \Bar.namereturnsfalseeven thoughBaris just inheriting its property fromFoo. This means that an implementation ofNSKeyValueObservingCustomizationcannot possibly work properly on anything besides a non-finalclass. Even if keypath construction in this instance were changed such that\Bar.namereturns the same thing as\Foo.name, the same cannot be done for the more complicated case[…]
I guess the workaround is to use the string-based Objective-C methods instead of the AnyKeyPath Swift ones.
See also: SR-9077.
NSKeyValueObservingCustomizationrelies on a global table to mapStringkey paths back intoAnyKeyPathvalues. However, as the string keypath does not include the root type, this means that observing properties with the same name on separate objects will overwrite each other in the global table. In a single-threaded scenario this is acceptable as theNSKeyValueObservingCustomizationmethods are invoked synchronously when the observation is created, and the global table is populated immediately prior to creating the observation. However, in a multithreaded scenario, the global keypath table could be overwritten with a different keypath prior to invoking theNSKeyValueObservingCustomizationmethod.