Core Data Model Attributes and NSManagedObject Property Types Must Match!

I admit – it might have taken me less time to figure out my runtime exception if I hadn’t just migrated my project to Swift 3 when I encountered the bug.

That’s the problem isn’t it? You go in… you intend to do one thing. Before long, you’ve got 15 files with an M out to the right. The project builds (finally), but ah – then there’s runtime.

When the crash occurs, you’re never sure if it was an existing problem, or if it was caused by the code conversion. Who knows – maybe it’s both?

Perhaps this is a story more about code conversion than it is about Core Data. In any case, perhaps it’ll help a poor soul struggling to figure out why EXC_BAD_INSTRUCTION just happened.

Data model Attributes and NSManagedObject property types – Match ’em!

Whenever you’re creating a subclass of NSManagedObject for the Entities in your data model, you’re in a mapping process.

Each Attribute on an Entity maps over to a property on the NSManagedObjectSubclass.

Not only must the names of those Attributes and properties match, but the Types of each must match as well.

Optionals are Types

String isn’t the same as String?.

Date isn’t the same as Date?.

They’re different Types.

So what happens if you specify that a certain Attribute named, say, createdOn is a Date with the Optional checkbox checked in the data model designer like this:

createdOn as Optional attribute

And over in the implementation of your NSManagedObject subclass, you have code that’s written like this:

What’ll happen? Well, I can tell you what’ll happen. :]

When you run the app and attempt to load objects from your persistent store that have been saved with nil for the createdOn value, your app will blow up:EXC_BAD_INSTRUCTION

Xcode isn’t entirely unhelpful. While the EXC_BAD_INSTRUCTION message in the text editor isn’t very illuminating, the Debug Navigator on the left (Debug navigator - 6th icon from left in the left sidebar) provides some clues.

For me, it displayed just the breadcrumb that made me go, “Oh! Let me go check and see if I’ve got a Type mis-match between my data model and my NSManagedObject subclass”:

Unconditionally bridge from Objective C NSDate? to Date

Interesting… It looks like there was an attempt to go from an NSDate? (optional) instance to a Date (non-optional).

The issue isn’t that I’ve got a mismatch between NSDate and Date. The runtime can swap those around and substitute them easily.

Rather, it’s that I’m trying to go from optional, where nil is fine, to non-optional, where nil…well…crashes things.

Lessons learned

What have I learned?

1 – Map Attributes to NSManagedObject subclass properties carefully.
2 – Don’t accidentally miss a ? to indicate that a property is optional if I’ve got it marked as optional in the data model
3 – Read the Debug Navigator. It’s not just a list of gibberish – it can actually provide helpful clues so you know where to go look to solve your problem!