53

I have set up one of my core data attributes as a Boolean. Now, I need to set it, but XCode keeps telling me that it may not respond to setUseGPS.

[ride setUseGPS: useGPS.on];

What is the method for setting a boolean in core data? All my other attributes are set this way, and they work great. So, not sure why a boolean does not work to be set this way?

Nic Hubbard
  • 41,587
  • 63
  • 251
  • 412

4 Answers4

134

Core Data "does not have" a Boolean type (it does, but it is an NSNumber).

So to set the equivalent of useGPS = YES.

[entity setUseGPS:[NSNumber numberWithBool:YES]];

And the other way around:

BOOL isGPSOn = [[entity useGPS] boolValue];

Update: As pointed out by SKG, With literals in Objetive-C you can now do it in a simpler way:

[entity setUseGPS:@YES];

BOOL isGPSOn = entity.useGPS.boolValue;
RickiG
  • 11,380
  • 13
  • 81
  • 120
18

As an alternative approach to the accepted answer, you can simply change the typing from an NSNumber* to a BOOL in the managed object interface definition, such as:

@property (nonatomic) BOOL useGPS;   // Notice that the 'retain' is also removed as we're now dealing with a scalar rather than an NSObject

Various alternative approaches are discussed here, but Chris Hanson's response was most illuminating for me, especially:

If you have a numeric attribute (including a boolean attribute) that's required, you can just type it as a scalar instead, and Core Data will do the right thing:

@property (nonatomic) BOOL isDone;

Even if the attribute is optional, that'll still work - it'll just conflate "not present" with "false."

and for a more aligned Cocoa implementation:

One other thing you might want to do is name the property "done" and just specify the getter as "isDone." That's the usual Cocoa naming convention:

@property (nonatomic, getter=isDone) BOOL done;

Then you can write "if (item.done) { ... }" or "item.done = NO;" and the compiler will still generate -isDone for accesses of the property.

Thanks Chris, and hope that this helps someone.

Community
  • 1
  • 1
paulkmoore
  • 3,253
  • 2
  • 21
  • 20
  • 1
    I'm seeing a crash on iOS 4.x when I try this method. Here's the message: "Property 'bar' is a scalar type on class 'Foo'. Cannot generate a getter method for it." I've tried setting the attribute type to Boolean in the Core Data model, and I've also tried Integer 16. I get the same crash either way. Am I missing something? Perhaps I'll just go back to using NSNumber. – Josh Brown Feb 02 '12 at 19:31
  • 2
    As far as I know, this does not work on NSManagedObject subclasses. – flagoworld Jan 14 '13 at 22:16
2

Just to complement @RickiG answer, the way to create a NSNumber from a Booland vice-versa in Swift (at least since v4.2) is:

let nsNumberFromBool = NSNumber(booleanLiteral: true) // or false
let boolFromNSNumber = nsNumberFromBool.boolValue
0

The "fix" for this (IMHO, it's a bug in Apple's SDK) is to add the following code to your CoreData-generated class. NB: if you do this in a category, in a separate file, then you don't have to re-copy/paste it each time you regenerate the CoreData classes inside Xcode

- (BOOL)useGPS
{
    [self willAccessValueForKey:@"useGPS"];
    BOOL myuseGPS = [[self primitiveUseGPS] boolValue];
    [self didAccessValueForKey:@"useGPS"];
    return myuseGPS;
}

- (void)setUseGPS:(BOOL)newValue
{
    [self willChangeValueForKey:@"useGPS"];
    [self setPrimitiveUseGPS:[NSNumber numberWithBool:newValue]];
    [self didChangeValueForKey:@"useGPS"];
}
Adam
  • 32,900
  • 16
  • 126
  • 153
  • This leads to conflicting types when I compile. Should I be changing the types of the existing NSNumber properties? – Daniel Wood Jan 15 '11 at 12:02
  • @Daniel Wood - don't change the existing types: CoreData requires them to be NSNumber. The compile warnings are irritating - the easy workaround is to rename the above two methods to "useGPSAsBool" and "setUseGPSAsBool". NB: you can still access the property, only it's now called "GPSAsBool", e.g. "if( myCoreDataObject.GPSAsBool )" – Adam Jan 15 '11 at 15:05
  • After reading the following in the docs I decided not to bother with any of this and just convert from NSNumber in my code: "The advantages of allowing Core Data to manage its own storage usually outweigh any advantages of interacting directly with scalar values" http://developer.apple.com/library/iOS/#documentation/Cocoa/Conceptual/CoreData/Articles/cdNSAttributes.html – Daniel Wood Jan 16 '11 at 20:18
  • @Daniel - the text you quote is referring to a different issue. That text does NOT apply in this case - we are indeed "allowing Core Data to manage its own storage", we're just adding 2 convenience methods to make it use booleans the way that ObjectiveC expects. I expect that Apple will eventually add a fix to their own code that is essentially the same as this. – Adam Jan 16 '11 at 20:33