Here is a bug that’s taken me about three years to track down:
- Create a Core Data entity
- Give it a relationship, say foo
- Have Core Data generate accessor methods for it
- Write your own -isFoo method on the same class
- Scratch your head while watching subtle calamities unfold
Some code if it helps clarify:
Yes, this seems some odd code to have. But Sandvox’s data model happens to have done so in one particular place.
So for quite some time now, I’ve been very frustrated — and mystified — that this particular managed object subclass of ours throws an exception whenever you attempt to get its -description. As you might imagine, this can be quite a pain while debugging!
How can this be?! The exception in question states that NSNumber does not respond to -objectID. I’m well aware of that fact! Hmmmm. The stack trace sheds no further light. The object is persisted properly, so we don’t seem to have broken Core Data in any fundamental way.
Finally today I stumbled upon the real cause. Another, rarely exercised, bit of our code uses -valueForKey: to retrieve the equivalent of foo, rather than call the getter method directly. It was blowing up because the object returned was of an unexpected class; NSNumber instead of our custom managed object. Sound familiar?
Looking at the implementation again, light was shed. -valueForKey: is documented to favour methods of the form isKey over key. So asking for @“key" calls the -isKey method, rather than -key as the caller likely expected!
It would seem that -[NSManagedObject description] is implemented internally to use -valueForKey:, and so when it tried to give me the managed object ID corresponding to a relationship, that threw an exception since what it got back was actually an NSNumber representing -isFoo.
Let’s face it, this is probably such an edge case I’m likely the only one who’s ever going to hit it. But maybe you will too someday, and, hopefully, Google will bring you here.
Update: Have been pleasantly surprised by a couple of people on Twitter telling me they’ve hit the same thing at some point in the past.