views:

151

answers:

2

I am working on an app that uses Core Data as its backend for managing SQLite records. I have everything working with strings and numbers, but have just tried adding BOOL fields and can't seem to get things to work.

In the .xcdatamodel, I have added a field to my object called isCurrentlyForSale which is not Optional, not Transient, and not Indexed. The attribute's type is set to Boolean with default value NO.

When I created the class files from the data model, the boilerplate code added for this property in the .h header was:

@property (nonatomic, retain) NSNumber * isCurrentlyForSale;

along with the

@dynamic isCurrentlyForSale;

in the .m implementation file.

I've always worked with booleans as simple BOOLs. I've read that I could use NSNumber's numberWithBool and boolValue methods, but this seems like an aweful lot of extra code for something so simple.

Can the @property in the header be changed to a simple BOOL? If so is there anything to watch out for?

Thanks -John

+1  A: 

Simple response: No, you cannot change the @property declaration to return a BOOL.

You can write some simple wrappers, though. I'd rename the attribute to currentlyForSale (which means it generates currentlyForSale and setCurrentlyForSale:), and then write two wrappers:

- (BOOL) isCurrentlyForSale {
  return [[self currentlyForSale] boolValue];
}

- (void) setIsCurrentlyForSale:(BOOL)forSale {
  [self setCurrentlyForSale:[NSNumber numberWithBool:forSale]];
}
Dave DeLong
A setter nor a property should have "is" in it. That is why `@property` has the `getter=` setting. And yes you can have the `@property` be changed to BOOL by using the primitive accessors that are part of Core Data.
Marcus S. Zarra
@Marcus Yes, I know that setters shouldn't have `Is` in them, but I put it in because `setCurrentlyForSale:` was already taken by CD (and I am aware of `getter=` and `setter=`. And are you saying that you can just change the `NSNumber *` to `BOOL` in the header and it'll work? That would *definitely* surprise me.
Dave DeLong
See my reply below. You need to implement your own accessors but it works just fine.
Marcus S. Zarra
+3  A: 

While Dave DeLong's answer is close, you can actually do this without having to change the name of the property.

You can change the property to return a BOOL but you need to then write the accessor methods by hand and they are a bit different than what Dave has in his response.

First your @property should be defined as:

@property (nonatomic, getter=isCurrentlyForSale) BOOL currentlyForSale;

Then in your implementation file, instead of declaring a @dynamic property, create the accessors directly.

- (BOOL)isCurrentlyForSale
{
  [self willAccessValueForKey:@"currentlyForSale"];
  BOOL b = [[self primitiveValueForKey:@"currentlyForSale"] boolValue];
  [self didAccessValueForKey:@"currentlyForSale"];
  return b;
}

- (void)setCurrentlyForSale:(BOOL)b
{
  [self willChangeValueForKey:@"currentlyForSale"];
  [self setPrimitiveValue:[NSNumber numberWithBool:b] forKey:@"currentlyForSale"];
  [self didChangeValueForKey:@"currentlyForSale"];
}

With these accessors your object will handle the boxing for you and you can access it as a primitive value. Also, a setter starting with setIs is not a great idea, hence the removal of it in the example code.

Marcus S. Zarra
+1 ah, I get what you're saying now. I thought you were implying that you could change the `@property` to `BOOL` and not implement custom methods. As an aside, the setter is slightly incorrect. The `(will|did)ChangeValueForKey:` should only be invoked if the new value is actually different (ie, you need an if statement).
Dave DeLong