I am the author of Core Data Fundamentals with Swift, CloudKit, iOS Data Persistence: The Big Picture, and eight other courses on Pluralsight.
Deepen your understanding by watching the courses!
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 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:
And over in the implementation of your NSManagedObject
subclass, you have code that’s written like this:
|
|
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:
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 () 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”:
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!