How do I create a KVO key-path to an array element?

I'm trying out KVO via KeyPaths in a macOS playground.

@objc final class Inner: NSObject {
    @objc dynamic var string1 = "string1"
    @objc dynamic var string2 = "string2"
}

@objc final class Outer: NSObject {
    @objc dynamic var string0 = "string0"
    @objc dynamic var array0 = [Inner(), Inner()]
}

let outer = Outer()
let allOptions: NSKeyValueObservingOptions = [.new, .old, .initial, .prior]
let watcher0 = outer.observe(\.self, options: allOptions) { (out, change) in
    print("0", change)
}
let watcher1 = outer.observe(\.string0, options: allOptions) { (out, change) in
    print("1", change)
}
let watcher2 = outer.observe(\.array0, options: allOptions) { (out, change) in
    print("2", change)
}
let watcher3 = outer.observe(\.array0[0].string1, options: allOptions) { (out, change) in
    print("3", change)
}

print("start", outer)
outer.string0 = "hello"
outer.array0[0].string1 = "world"
_ = outer.array0.removeFirst()
print("end", outer)

It's "watcher3" I'm not sure about. The playground keeps crashing on trying to create a path.

Fatal error: Could not extract a String from KeyPath Swift.ReferenceWritableKeyPath<__lldb_expr_3.Outer, Swift.String>: file /AppleInternal/BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang_overlay_Foundation/swiftlang-1103.8.25.8/swift/stdlib/public/Darwin/Foundation/NSObject.swift, line 155

Can elements within an @objc Array be watched? Am I using the right key path. Is using that key path, assuming it's right, the right way to observe? If not, what is (if possible)?

In Obj-C, you cannot run a KVO keypath "through" an array. I assume that to observe an Obj-C keypath, Swift has to derive a keypath string from its internal representation of a Swift keypath, and that's failing because there's no legal string it can produce.

In Obj-C, you can observe changes to an array (insertions, replacements and deletions). You can also add observations onto each object of the array. However, those two things are not related. The element observations are not adjusted when the array is changed.

In other words, Obj-C has no way of saying "I want to observe whatever object is first in the array", though Swift does, apparently.

Terms of Service

Privacy Policy

Cookie Policy