views:

121

answers:

2

Hello all,

I am adding a transient property to my Core Data-based app, and I think I am missing something. In the Data Model Editor, I added a optional, transient, BOOL property called isUnderwater.

In my model's header file, I added: @property (nonatomic) BOOL isUnderwater;, then I implemented these methods in the implementation file:

- (BOOL)isUnderwater {
    ... implementation ...
    return (ret);
}
- (void)setIsUnderwater:(BOOL)isUnderwater {}

But when I try to use isUnderwater as a condition in a NSPredicate, I get this error: *** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: 'keypath isUnderwater not found in entity <NSSQLEntity Wheel id=2>'.

Any ideas?

Thanks!

A: 

First, you can't use a transient property in a NSFetchRequest that is going against a SQLite store. When you are using SQLite the NSFetchRequest is translated into sql and run against the database, long before your transient is ever touched.

Also, you should not be implementing the accessors, you should be using @synthesize instead.

Next, if you are wanting to set the transient property then you should be setting it in the -awakeFromFetch and/or -awakeFromInsert instead of overriding the getter.

Next, your property should be called underwater and the @property definition should be:

@property (nonatomic, retain, getter=isUnderwater) NSNumber *underwater;

Note: even though you are declaring it a boolean in your model, it is still a NSNumber in code.

Lastly, setting the optional flag on a transient property has no value since it will be thrown away anyway.

Update

You can apply additional filters (even against transient properties) once the entities are in memory. The only limitation is that you can't use transient properties when you are going out to the SQLite file.

For example, you could perform a NSFetchRequest that loads in all of the entities. You could then immediately apply a second NSPredicate against the returned NSArray and further filter the objects down.

Marcus S. Zarra
That makes sense. But how does one populate a UITableView with core data objects that are filtered based on custom logic rather than stored / non-transient attributes? For example, if I wanted to be able to switch between all objects of a type and those that have a transient property set a certain way (i.e., pass a certain logic test)? I would think to use blocks, but those are unavailable as well against an SQLite store...
Bill Smithed
It's perfectly valid to override the getter (especially since neither you nor I have any idea what he's doing in there). It's also perfectly find to use a BOOL on a transient property that is actually a BOOL. There is no reason at all to box and unbox in an NSNumber--especially since he's providing his own NSManagedObject subclass. I often do this with managed attributes that are backed by a primitive to make access easier.
Jason Coco
@Jason it is bad form to override accessors with custom logic. If you are working with a property the accessor should only access the value; not perform custom logic. In addition, if you are declaring a transient `NSNumber` as a `BOOL` you are asking for trouble. Might work today, but I seriously doubt it will always work. I won't recommend it.
Marcus S. Zarra
`you could perform a NSFetchRequest that loads in all of the entities. You could then immediately apply a second NSPredicate against the returned NSArray and further filter the objects down.` So does this mean then that an NSFetchedResultsController is "off the table"?
Bill Smithed
No, just a bit more complicated. You can still use it for the purpose of detecting changes in the data but you would need to update your secondary array whenever those changes come in. Personally I would find a way to make that transient property a stored property instead. De-normalizing data tends to solve a lot of problems like these.
Marcus S. Zarra
A: 

Alternatively you could create a suitable NSManagedObject validate method: http://stackoverflow.com/questions/1022284/what-is-the-type-for-boolean-attributes-in-core-data-entities/3934284#3934284

OOP_Master