I've experienced repeatable crashes in an iOS app using KVO, and I'm wondering if anyone else is having the same issue. This is in Xcode 11 beta 7 running in Catalina beta 7 on the iPhone XR simulator. My project targets iOS 11 as a minimum deployment, but I was able to reproduce this issue in a very simple project that targets iOS 13.
Here's the pertinent code from my simple demo:
Create a class to observe:
class ObservableObject: NSObject {
dynamic var purchaseInProgress = false
dynamic var wasPurchased = false
var name = ""
init(name: String) {
self.name = name
}
}
In a view controller, add an iVar for a strong reference to an observers array, and an array of observable objects:
var observers = [NSKeyValueObservation]()
var products = [ObservableObject]()
Be sure to initialized the products array with some values:
override func viewDidLoad() {
super.viewDidLoad()
products.append(ObservableObject(name: "Hot Fudge Sundae"))
products.append(ObservableObject(name: "Deluxe Cheeseburger"))
}
Then add an outlet to a button that can trigger the action, and a method that should be called when an object is changed:
@IBAction func setupObservers() {
let purchaseProgressKeyPath = \ObservableObject.purchaseInProgress
let wasPurchasedKeyPath = \ObservableObject.wasPurchased
for product in products {
self.observers.append(product.observe(purchaseProgressKeyPath, changeHandler: { (changedProduct, change) in
self.productWasChanged(changedProduct)
}))
self.observers.append(product.observe(wasPurchasedKeyPath, changeHandler: { (changedProduct, change) in
self.productWasChanged(changedProduct)
}))
}
}
@objc func productWasChanged(_ product: ObservableObject) {
}
Run the project and watch it crash with:
Fatal error: Could not extract a String from KeyPath Swift.ReferenceWritableKeyPath<KVOCrash.ObservableObject, Swift.Bool>: file /BuildRoot/Library/Caches/com.apple.xbs/Sources/swiftlang_overlay_Foundation_Sim/swiftlang-1100.2.259.50/swift/stdlib/public/Darwin/Foundation/NSObject.swift, line 155
At least that's my result. I hope this is something Apple needs to, and will, fix. This example is borrowed from more complex code that's working just fine in Xcode 10 but crashing in the Xcode 11 beta 7.