How to Use Boolean Attributes in Core Data
Some Context:
The data model of my current project started breaking after I versioned it to #7, rejecting my usage of Booleans. Part of my confusion was due to this selective, late-in-the-game breakage: booleans had been working fine up until now, and I hadn’t changed anything that I recall; #7 added a new transient attribute to a different entity. Shouldn’t they have been breaking from day 1?
I searched fruitlessly for “How to Use Boolean Attributes in Core Data” and variations on that theme, to no avail (excuse the redundancy). Only after I had this explained to me in person did I realize that the answers were out there, obliquely (amongst the usual suspects: a Stack Overflow post, or this one, and in a few posts years old).
So you’ll forgive me if I broadcast and blast that phrase repeatedly, in the hopes of raising the SEO rankings for “How to Use Boolean Attributes in Core Data.” If you’re reading this, there’s a good chance you’re happy that I did. And if you’re unhappy, well, there are pills for that.
How to Use Boolean Attributes in Core Data
tl;dr:
The Simple Way
- Check the “Use scalar properties for primitive data types” checkbox while auto-generating your subclasses.
- Grab a beer.
The Objective Way
- Instead of YES and NO , use @YES and @NO .
- For control flow purposes (i.e., logical tests), call the boolValue .
Discussion
The opposite of a fact is falsehood, but the opposite of one profound truth may very well be another profound truth.
Do all AIBOs go to robot heaven? Do androids dream of electric sheep? Can Core Data keep track of profound truths? Yes, yes, and yes.
The limitation of scalars is that they must be, or not be, without question: 0/1, YES/NO. But opposite of ‘existence’ is not ‘death’ or ‘sadness’ or any something — it is non-existence.
In Objective-C, what indicates non-existence? nil. If you need your attribute to have this capability, you need objects, such as NSNumber (ty CH for pointing this out).
Conversely, if you get errors with your boolean (see below), check to see if they are not actually NSNumbers. Two Things to be aware of then:
Thing #1: Setting the Entity’s value — You have added a boolean attribute to your entity in the data model, and had Xcode generate your model classes from it. You might think to code something like so:
myManagedObject.someBool = YES; //[WRONG]
You will probably get a warning along the lines of “makes pointer from integer without a cast.” This is because, as mentioned above, Core Data defaults to avoid booleans and other scalars, and so the attribute is stored as an NSNumber. Check your managed object header file (iOS 9: +coreDataProperties header), and you’ll see:
@property (nonatomic, retain) NSNumber *someBool;
So instead, set the NSNumber like so:
myManagedObject.someBool = @YES; //[CORRECT]
Thing #2: Accessing the Entity’s value — In control flow statements, or wherever you are testing for the logical value of your boolean, you must always use the boolValue, because while NO is ‘zip, zilch, 0’, @NO
evaluates to true (it exists)!
Instead, use boolValue
:
Good hunting, peoples!