We have an app with a fairly broad Core Data model, with lots of custom subclasses implemented in Objective C, but which are also used by a growing fraction of the app that's written in Swift. (For what it's worth: we're building with Xcode 7.3.1 against iOS 9.3, and the Swift code is thus 2.2.)
There's a helper function written in Swift that looks like this:
extension NSManagedObject {
func inContext<T: NSManagedObject>(moc: NSManagedObjectContext) -> T? {
guard self.managedObjectContext != moc else {
return (self as! T)
}
do {
let obj = try moc.existingObjectWithID(self.objectID)
return (obj as! T) // <--- fails here
}
catch let error {
return nil
}
}
}
This is called in a fair number of places where objects jump contexts. Calling code generally looks like this:
let result: ECFoo? = foo.inContext(managedObjectContext)
This works flawlessly in debug builds of the app. But with optimizations turned on, I'm running into a case where this call fails at the line I've marked, where the fetched object is being cast from NSManagedObject
to the correct subclass. The stack trace starts with swift_dynamicCastObjCClassUnconditional
, and the message that gets logged to the console is:
Could not cast value of type 'ECFoo_Foo_' (0x7fb857d2c250) to 'ECFoo_Foo_' (0x7fb857d2c250).
If I put a breakpoint on that line, what I'm attempting to do seems fine in the debugger console:
(lldb) po moc.existingObjectWithID(self.objectID) is ECFoo
true
This is deeply confusing, because it's clearly the same type on both sides here, and they both appear to be the dynamically generated subclass, rather than the formal class that it should be trying to cast to (based on inference of the calling code). I can only assume that there's some piece of information being optimized away that is necessary to make this work, but I'm not entirely sure how to fix it.